return gdk_content_provider_new_typed (GDK_TYPE_TEXTURE, paintable);
}
-static void
-got_texture (GObject *source,
- GAsyncResult *result,
- gpointer data)
-{
- GdkDrop *drop = GDK_DROP (source);
- GtkWidget *image = data;
- const GValue *value;
- GError *error = NULL;
-
- value = gdk_drop_read_value_finish (drop, result, &error);
- if (value)
- {
- GdkTexture *texture = g_value_get_object (value);
- gtk_image_set_from_paintable (GTK_IMAGE (image), GDK_PAINTABLE (texture));
- }
- else
- {
- g_print ("Failed to get data: %s\n", error->message);
- g_error_free (error);
- }
-}
-
static gboolean
drag_drop (GtkDropTarget *dest,
- GdkDrop *drop,
- int x,
- int y,
- GtkWidget *widget)
+ const GValue *value,
+ double x,
+ double y,
+ GtkImage *image)
{
- if (gdk_drop_has_value (drop, GDK_TYPE_TEXTURE))
- {
- gdk_drop_read_value_async (drop, GDK_TYPE_TEXTURE, G_PRIORITY_DEFAULT, NULL, got_texture, widget);
- return TRUE;
- }
+ GdkTexture *texture = g_value_get_object (value);
+ gtk_image_set_from_paintable (GTK_IMAGE (image), GDK_PAINTABLE (texture));
- return FALSE;
+ return TRUE;
}
static void
gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (source));
/* accept drops on image */
- dest = gtk_drop_target_new (gdk_content_formats_new_for_gtype (GDK_TYPE_TEXTURE), GDK_ACTION_COPY);
- g_signal_connect (dest, "drag-drop", G_CALLBACK (drag_drop), image);
+ dest = gtk_drop_target_new (GDK_TYPE_TEXTURE, GDK_ACTION_COPY);
+ g_signal_connect (dest, "drop", G_CALLBACK (drag_drop), image);
gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (dest));
/* context menu on image */
gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (source));
/* accept drops on image */
- dest = gtk_drop_target_new (gdk_content_formats_new_for_gtype (GDK_TYPE_TEXTURE), GDK_ACTION_COPY);
- g_signal_connect (dest, "drag-drop", G_CALLBACK (drag_drop), image);
+ dest = gtk_drop_target_new (GDK_TYPE_TEXTURE, GDK_ACTION_COPY);
+ g_signal_connect (dest, "drop", G_CALLBACK (drag_drop), image);
gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (dest));
/* context menu on image */
<FILE>gtkdroptarget</FILE>
GtkDropTarget
gtk_drop_target_new
-gtk_drop_target_set_formats
+gtk_drop_target_set_gtypes
+gtk_drop_target_get_gtypes
gtk_drop_target_get_formats
gtk_drop_target_set_actions
gtk_drop_target_get_actions
+gtk_drop_target_set_preload
+gtk_drop_target_get_preload
gtk_drop_target_get_drop
-gtk_drop_target_find_mimetype
-gtk_drag_highlight
-gtk_drag_unhighlight
+gtk_drop_target_get_value
+gtk_drop_target_reject
<SUBSECTION Standard>
GTK_TYPE_DROP_TARGET
gtk_drop_target_get_type
</SECTION>
+<SECTION>
+<FILE>gtkdroptargetasync</FILE>
+GtkDropTargetAsync
+gtk_drop_target_async_new
+gtk_drop_target_async_set_formats
+gtk_drop_target_async_get_formats
+gtk_drop_target_async_set_actions
+gtk_drop_target_async_get_actions
+gtk_drop_target_async_reject_drop
+
+<SUBSECTION Standard>
+GTK_TYPE_DROP_TARGET_ASYNC
+GTK_DROP_TARGET_ASYNC
+GTK_DROP_TARGET_ASYNC_CLASS
+GTK_IS_DROP_TARGET_ASYNC
+GTK_IS_DROP_TARGET_ASYNC_CLASS
+GTK_DROP_TARGET_ASYNC_GET_CLASS
+<SUBSECTION Private>
+gtk_drop_target_async_get_type
+</SECTION>
+
<SECTION>
<FILE>gtkdropcontrollermotion</FILE>
<TITLE>GtkDropControllerMotion</TITLE>
#include <gtk/gtkcustomlayout.h>
#include <gtk/gtkdebug.h>
#include <gtk/gtkdialog.h>
-#include <gtk/gtkdragdest.h>
#include <gtk/gtkdragicon.h>
#include <gtk/gtkdragsource.h>
#include <gtk/gtkdrawingarea.h>
#include <gtk/gtkdropcontrollermotion.h>
+#include <gtk/gtkdroptarget.h>
+#include <gtk/gtkdroptargetasync.h>
#include <gtk/gtkeditable.h>
#include <gtk/gtkemojichooser.h>
#include <gtk/gtkentry.h>
#endif
#include "gtkcalendar.h"
-#include "gtkdragdest.h"
+#include "gtkdroptarget.h"
#include "gtkintl.h"
#include "gtkmain.h"
#include "gtkmarshalers.h"
GtkWidget *widget);
static void gtk_calendar_state_flags_changed (GtkWidget *widget,
GtkStateFlags previous_state);
-static gboolean gtk_calendar_drag_accept (GtkDropTarget *dest,
- GdkDrop *drop,
- GtkCalendar *calendar);
-static void gtk_calendar_drag_leave (GtkDropTarget *dest,
- GdkDrop *drop,
- GtkCalendar *calendar);
-static gboolean gtk_calendar_drag_drop (GtkDropTarget *dest,
- GdkDrop *drop,
- int x,
- int y,
- GtkCalendar *calendar);
static void calendar_invalidate_day (GtkCalendar *widget,
G_DEFINE_TYPE_WITH_PRIVATE (GtkCalendar, gtk_calendar, GTK_TYPE_WIDGET)
+static void
+gtk_calendar_drag_notify_value (GtkDropTarget *target,
+ GParamSpec **pspec,
+ GtkCalendar *calendar)
+{
+ GDate *date;
+ const GValue *value;
+
+ value = gtk_drop_target_get_value (target);
+ if (value == NULL)
+ return;
+
+ date = g_date_new ();
+ g_date_set_parse (date, g_value_get_string (value));
+ if (!g_date_valid (date))
+ gtk_drop_target_reject (target);
+ g_date_free (date);
+}
+
+static gboolean
+gtk_calendar_drag_drop (GtkDropTarget *dest,
+ const GValue *value,
+ double x,
+ double y,
+ GtkCalendar *calendar)
+{
+ GDate *date;
+ GDateTime *datetime;
+
+ date = g_date_new ();
+ g_date_set_parse (date, g_value_get_string (value));
+
+ if (!g_date_valid (date))
+ {
+ g_warning ("Received invalid date data");
+ g_date_free (date);
+ return FALSE;
+ }
+
+ datetime = g_date_time_new_local (g_date_get_year (date),
+ g_date_get_month (date),
+ g_date_get_day (date),
+ 0, 0, 0);
+ g_date_free (date);
+
+ gtk_calendar_select_day (calendar, datetime);
+ g_date_time_unref (datetime);
+
+ return TRUE;
+}
+
static void
gtk_calendar_dispose (GObject *object)
{
GtkWidget *widget = GTK_WIDGET (calendar);
GtkEventController *controller;
GtkGesture *gesture;
+ GtkDropTarget *target;
gint i;
#ifdef G_OS_WIN32
wchar_t wbuffer[100];
#else
gchar *week_start;
#endif
- GtkDropTarget *dest;
int min_year_width;
GDateTime *now;
priv->in_drag = 0;
- dest = gtk_drop_target_new (gdk_content_formats_new_for_gtype (G_TYPE_STRING),
- GDK_ACTION_COPY);
-
- g_signal_connect (dest, "accept", G_CALLBACK (gtk_calendar_drag_accept), calendar);
- g_signal_connect (dest, "drag-leave", G_CALLBACK (gtk_calendar_drag_leave), calendar);
- g_signal_connect (dest, "drag-drop", G_CALLBACK (gtk_calendar_drag_drop), calendar);
-
- gtk_widget_add_controller (widget, GTK_EVENT_CONTROLLER (dest));
+ target = gtk_drop_target_new (G_TYPE_STRING, GDK_ACTION_COPY);
+ gtk_drop_target_set_preload (target, TRUE);
+ g_signal_connect (target, "notify::value", G_CALLBACK (gtk_calendar_drag_notify_value), calendar);
+ g_signal_connect (target, "drop", G_CALLBACK (gtk_calendar_drag_drop), calendar);
+ gtk_widget_add_controller (widget, GTK_EVENT_CONTROLLER (target));
priv->year_before = 0;
}
}
-/* Get/set whether drag_motion requested the drag data and
- * drag_data_received should thus not actually insert the data,
- * since the data doesn’t result from a drop.
- */
-static void
-set_status_pending (GdkDrop *drop,
- GdkDragAction suggested_action)
-{
- g_object_set_data (G_OBJECT (drop),
- I_("gtk-calendar-status-pending"),
- GINT_TO_POINTER (suggested_action));
-}
-
-static GdkDragAction
-get_status_pending (GdkDrop *drop)
-{
- return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (drop),
- "gtk-calendar-status-pending"));
-}
-
-static void
-gtk_calendar_drag_leave (GtkDropTarget *dest,
- GdkDrop *drop,
- GtkCalendar *calendar)
-{
-}
-
-static void
-got_text (GObject *source,
- GAsyncResult *result,
- gpointer data)
-{
- GtkDropTarget *dest = GTK_DROP_TARGET (data);
- GtkCalendar *calendar = GTK_CALENDAR (gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (dest)));
- GdkDrop *drop = GDK_DROP (source);
- gchar *str;
- GDate *date;
- GDateTime *datetime;
- GdkDragAction suggested_action;
-
- suggested_action = get_status_pending (drop);
- set_status_pending (drop, 0);
-
- str = gdk_drop_read_text_finish (drop, result, NULL);
-
- if (suggested_action)
- {
- if (str)
- {
- date = g_date_new ();
- g_date_set_parse (date, str);
- if (!g_date_valid (date))
- suggested_action = 0;
- g_date_free (date);
- g_free (str);
- }
- else
- suggested_action = 0;
- gdk_drop_status (drop, suggested_action);
- if (suggested_action == 0)
- gtk_drop_target_deny_drop (dest, drop);
- return;
- }
-
- date = g_date_new ();
- if (str)
- {
- g_date_set_parse (date, str);
- g_free (str);
- }
-
- if (!g_date_valid (date))
- {
- g_warning ("Received invalid date data");
- g_date_free (date);
- gdk_drop_finish (drop, 0);
- gtk_drop_target_deny_drop (dest, drop);
- return;
- }
-
- datetime = g_date_time_new_local (g_date_get_year (date),
- g_date_get_month (date),
- g_date_get_day (date),
- 0, 0, 0);
- g_date_free (date);
-
- gdk_drop_finish (drop, suggested_action);
-
- gtk_calendar_select_day (calendar, datetime);
- g_date_time_unref (datetime);
-}
-
-static gboolean
-gtk_calendar_drag_accept (GtkDropTarget *dest,
- GdkDrop *drop,
- GtkCalendar *calendar)
-{
- const char *target;
-
- target = gtk_drop_target_find_mimetype (dest);
- if (!target || gdk_drop_get_actions (drop) == 0)
- {
- gdk_drop_status (drop, 0);
- return FALSE;
- }
- else if (get_status_pending (drop) == 0)
- {
- set_status_pending (drop, gdk_drop_get_actions (drop));
- gdk_drop_read_text_async (drop, NULL, got_text, dest);
- }
- return TRUE;
-}
-
-static gboolean
-gtk_calendar_drag_drop (GtkDropTarget *dest,
- GdkDrop *drop,
- int x,
- int y,
- GtkCalendar *calendar)
-{
- const char *target;
-
- target = gtk_drop_target_find_mimetype (dest);
- if (target != NULL)
- {
- set_status_pending (drop, 0);
- gdk_drop_read_text_async (drop, NULL, got_text, dest);
- return TRUE;
- }
-
- return FALSE;
-}
-
\f
/****************************************
* Public API *
#include "gtkcolorchooserprivate.h"
#include "gtkcolorchooserdialog.h"
#include "gtkcolorswatchprivate.h"
-#include "gtkdragdest.h"
#include "gtkdragsource.h"
+#include "gtkdroptarget.h"
#include "gtkintl.h"
#include "gtkmain.h"
#include "gtkmarshalers.h"
#include "gtkprivate.h"
#include "gtksnapshot.h"
#include "gtkstylecontext.h"
-#include "gtkdragsource.h"
-#include "gtkdragdest.h"
-#include "gtkeventcontroller.h"
/**
gtk_widget_class_set_css_name (widget_class, "colorbutton");
}
-static void
-got_color (GObject *source,
- GAsyncResult *result,
- gpointer data)
-{
- GdkDrop *drop = GDK_DROP (source);
- const GValue *value;
-
- value = gdk_drop_read_value_finish (drop, result, NULL);
- if (value)
- {
- GdkRGBA *color = g_value_get_boxed (value);
- gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (data), color);
- gdk_drop_finish (drop, GDK_ACTION_COPY);
- }
- else
- gdk_drop_finish (drop, 0);
-}
-
static gboolean
-gtk_color_button_drag_drop (GtkDropTarget *dest,
- GdkDrop *drop,
- int x,
- int y,
- GtkColorButton *button)
+gtk_color_button_drop (GtkDropTarget *dest,
+ const GValue *value,
+ double x,
+ double y,
+ GtkColorButton *button)
{
- gdk_drop_read_value_async (drop, GDK_TYPE_RGBA, G_PRIORITY_DEFAULT, NULL, got_color, button);
+ GdkRGBA *color = g_value_get_boxed (value);
+
+ gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (button), color);
return TRUE;
}
priv->rgba.alpha = 1;
priv->use_alpha = FALSE;
- dest = gtk_drop_target_new (gdk_content_formats_new_for_gtype (GDK_TYPE_RGBA),
- GDK_ACTION_COPY);
- g_signal_connect (dest, "drag-drop", G_CALLBACK (gtk_color_button_drag_drop), button);
+ dest = gtk_drop_target_new (GDK_TYPE_RGBA, GDK_ACTION_COPY);
+ g_signal_connect (dest, "drop", G_CALLBACK (gtk_color_button_drop), button);
gtk_widget_add_controller (GTK_WIDGET (button), GTK_EVENT_CONTROLLER (dest));
source = gtk_drag_source_new ();
#include "gtkbox.h"
#include "gtkcolorchooserprivate.h"
#include "gtkcssnodeprivate.h"
-#include "gtkdragdest.h"
#include "gtkdragsource.h"
+#include "gtkdroptarget.h"
#include "gtkgesturelongpress.h"
#include "gtkgestureclick.h"
#include "gtkgesturesingle.h"
g_object_unref (paintable);
}
-static void
-got_color (GObject *source,
- GAsyncResult *result,
- gpointer data)
-{
- GdkDrop *drop = GDK_DROP (source);
- const GValue *value;
-
- value = gdk_drop_read_value_finish (drop, result, NULL);
- if (value)
- {
- GdkRGBA *color = g_value_get_boxed (value);
- gtk_color_swatch_set_rgba (GTK_COLOR_SWATCH (data), color);
- gdk_drop_finish (drop, GDK_ACTION_COPY);
- }
- else
- gdk_drop_finish (drop, 0);
-}
-
static gboolean
swatch_drag_drop (GtkDropTarget *dest,
- GdkDrop *drop,
- int x,
- int y,
+ const GValue *value,
+ double x,
+ double y,
GtkColorSwatch *swatch)
+
{
- gdk_drop_read_value_async (drop, GDK_TYPE_RGBA, G_PRIORITY_DEFAULT, NULL, got_color, swatch);
+ gtk_color_swatch_set_rgba (swatch, g_value_get_boxed (value));
+
return TRUE;
}
if (can_drop && !priv->dest)
{
- priv->dest = gtk_drop_target_new (gdk_content_formats_new_for_gtype (GDK_TYPE_RGBA),
- GDK_ACTION_COPY);
- g_signal_connect (priv->dest, "drag-drop", G_CALLBACK (swatch_drag_drop), swatch);
+ priv->dest = gtk_drop_target_new (GDK_TYPE_RGBA, GDK_ACTION_COPY);
+ g_signal_connect (priv->dest, "drop", G_CALLBACK (swatch_drag_drop), swatch);
gtk_widget_add_controller (GTK_WIDGET (swatch), GTK_EVENT_CONTROLLER (priv->dest));
}
if (!can_drop && priv->dest)
+++ /dev/null
-/* GTK - The GIMP Toolkit
- * Copyright (C) 1995-1999 Peter Mattis, Spencer Kimball and Josh MacDonald
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
- * file for a list of people on the GTK+ Team. See the ChangeLog
- * files for a list of changes. These files are distributed with
- * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
- */
-
-#include "config.h"
-
-#include "gtkdragdest.h"
-#include "gtkdragdestprivate.h"
-
-#include "gtkintl.h"
-#include "gtknative.h"
-#include "gtktypebuiltins.h"
-#include "gtkeventcontrollerprivate.h"
-#include "gtkmarshalers.h"
-
-
-/**
- * SECTION:gtkdroptarget
- * @Short_description: Event controller to receive DND drops
- * @Title: GtkDropTarget
- *
- * GtkDropTarget is an auxiliary object that is used to receive
- * Drag-and-Drop operations.
- *
- * To use a GtkDropTarget to receive drops on a widget, you create
- * a GtkDropTarget object, configure which data formats and actions
- * you support, connect to its signals, and then attach
- * it to the widget with gtk_widget_add_controller().
- *
- * During a drag operation, the first signal that a GtkDropTarget
- * emits is #GtkDropTarget::accept, which is meant to determine
- * whether the target is a possible drop site for the ongoing drag.
- * The default handler for the ::accept signal accepts the drag
- * if it finds a compatible data format an an action that is supported
- * on both sides.
- *
- * If it is, and the widget becomes the current target, you will
- * receive a #GtkDropTarget::drag-enter signal, followed by
- * #GtkDropTarget::drag-motion signals as the pointer moves, and
- * finally either a #GtkDropTarget::drag-leave signal when the pointer
- * move off the widget, or a #GtkDropTarget::drag-drop signal when
- * a drop happens.
- *
- * The ::drag-enter and ::drag-motion handler can call gdk_drop_status()
- * to update the status of the ongoing operation. The ::drag-drop handler
- * should initiate the data transfer and finish the operation by calling
- * gdk_drop_finish().
- *
- * Between the ::drag-enter and ::drag-leave signals the widget is the
- * current drop target, and will receive the %GTK_STATE_FLAG_DROP_ACTIVE
- * state, which can be used to style the widget as a drop targett.
- */
-
-struct _GtkDropTarget
-{
- GtkEventController parent_object;
-
- GdkContentFormats *formats;
- GdkDragAction actions;
-
- GtkWidget *widget;
- GdkDrop *drop;
- gboolean contains;
- gboolean contains_pending;
-};
-
-struct _GtkDropTargetClass
-{
- GtkEventControllerClass parent_class;
-
- gboolean (*accept ) (GtkDropTarget *dest,
- GdkDrop *drop);
-};
-
-enum {
- PROP_FORMATS = 1,
- PROP_ACTIONS,
- PROP_CONTAINS,
- NUM_PROPERTIES
-};
-
-static GParamSpec *properties[NUM_PROPERTIES];
-
-enum {
- ACCEPT,
- DRAG_ENTER,
- DRAG_MOTION,
- DRAG_LEAVE,
- DRAG_DROP,
- NUM_SIGNALS
-};
-
-static guint signals[NUM_SIGNALS];
-
-static gboolean gtk_drop_target_accept (GtkDropTarget *dest,
- GdkDrop *drop);
-
-static gboolean gtk_drop_target_handle_event (GtkEventController *controller,
- GdkEvent *event,
- double x,
- double y);
-static gboolean gtk_drop_target_filter_event (GtkEventController *controller,
- GdkEvent *event);
-
-static gboolean gtk_drop_target_get_contains (GtkDropTarget *dest);
-static void gtk_drop_target_set_contains (GtkDropTarget *dest,
- gboolean contains);
-
-typedef enum {
- GTK_DROP_STATUS_NONE,
- GTK_DROP_STATUS_ACCEPTED,
- GTK_DROP_STATUS_DENIED
-} GtkDropStatus;
-
-static GtkDropStatus gtk_drop_target_get_drop_status (GtkDropTarget *dest,
- GdkDrop *drop);
-static void gtk_drop_target_set_drop_status (GtkDropTarget *dest,
- GdkDrop *drop,
- GtkDropStatus status);
-
-G_DEFINE_TYPE (GtkDropTarget, gtk_drop_target, GTK_TYPE_EVENT_CONTROLLER);
-
-static void
-gtk_drop_target_init (GtkDropTarget *dest)
-{
-}
-
-static void
-gtk_drop_target_finalize (GObject *object)
-{
- GtkDropTarget *dest = GTK_DROP_TARGET (object);
-
- g_clear_pointer (&dest->formats, gdk_content_formats_unref);
-
- G_OBJECT_CLASS (gtk_drop_target_parent_class)->finalize (object);
-}
-
-static void
-gtk_drop_target_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- GtkDropTarget *dest = GTK_DROP_TARGET (object);
-
- switch (prop_id)
- {
- case PROP_FORMATS:
- gtk_drop_target_set_formats (dest, g_value_get_boxed (value));
- break;
-
- case PROP_ACTIONS:
- gtk_drop_target_set_actions (dest, g_value_get_flags (value));
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-gtk_drop_target_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- GtkDropTarget *dest = GTK_DROP_TARGET (object);
-
- switch (prop_id)
- {
- case PROP_FORMATS:
- g_value_set_boxed (value, gtk_drop_target_get_formats (dest));
- break;
-
- case PROP_ACTIONS:
- g_value_set_flags (value, gtk_drop_target_get_actions (dest));
- break;
-
- case PROP_CONTAINS:
- g_value_set_boolean (value, gtk_drop_target_get_contains (dest));
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-gtk_drop_target_class_init (GtkDropTargetClass *class)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (class);
- GtkEventControllerClass *controller_class = GTK_EVENT_CONTROLLER_CLASS (class);
-
- object_class->finalize = gtk_drop_target_finalize;
- object_class->set_property = gtk_drop_target_set_property;
- object_class->get_property = gtk_drop_target_get_property;
-
- controller_class->handle_event = gtk_drop_target_handle_event;
- controller_class->filter_event = gtk_drop_target_filter_event;
-
- class->accept = gtk_drop_target_accept;
-
- /**
- * GtkDropTarget:formats:
- *
- * The #GdkContentFormats that determines the supported data formats
- */
- properties[PROP_FORMATS] =
- g_param_spec_boxed ("formats", P_("Formats"), P_("Formats"),
- GDK_TYPE_CONTENT_FORMATS,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
-
- /**
- * GtkDropTarget:actions:
- *
- * The #GdkDragActions that this drop target supports
- */
- properties[PROP_ACTIONS] =
- g_param_spec_flags ("actions", P_("Actions"), P_("Actions"),
- GDK_TYPE_DRAG_ACTION, 0,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
-
- /**
- * GtkDropTarget:contains:
- *
- * Whether the drop target is currently the targed of an ongoing drag operation,
- * and highlighted.
- */
- properties[PROP_CONTAINS] =
- g_param_spec_boolean ("contains", P_("Contains an ongoing drag"), P_("Contains the current drag"),
- FALSE,
- G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
-
- g_object_class_install_properties (object_class, NUM_PROPERTIES, properties);
-
- /**
- * GtkDropTarget::drag-enter:
- * @dest: the #GtkDropTarget
- * @drop: the #GdkDrop
- *
- * The ::drag-enter signal is emitted on the drop site when the cursor
- * enters the widget. It can be used to set up custom highlighting.
- */
- signals[DRAG_ENTER] =
- g_signal_new (I_("drag-enter"),
- G_TYPE_FROM_CLASS (class),
- G_SIGNAL_RUN_LAST,
- 0,
- NULL, NULL,
- NULL,
- G_TYPE_NONE, 1,
- GDK_TYPE_DROP);
-
- /**
- * GtkDropTarget::drag-leave:
- * @dest: the #GtkDropTarget
- * @drop: the #GdkDrop
- *
- * The ::drag-leave signal is emitted on the drop site when the cursor
- * leaves the widget. Its main purpose it to undo things done in
- * #GtkDropTarget::drag-enter.
- */
- signals[DRAG_LEAVE] =
- g_signal_new (I_("drag-leave"),
- G_TYPE_FROM_CLASS (class),
- G_SIGNAL_RUN_LAST,
- 0,
- NULL, NULL,
- NULL,
- G_TYPE_NONE, 1,
- GDK_TYPE_DROP);
-
- /**
- * GtkDropTarget::drag-motion:
- * @dest: the #GtkDropTarget
- * @drop: the #GdkDrop
- * @x: the x coordinate of the current cursor position
- * @y: the y coordinate of the current cursor position
- *
- * The ::drag motion signal is emitted while the pointer is moving
- * over the drop target.
- */
- signals[DRAG_MOTION] =
- g_signal_new (I_("drag-motion"),
- G_TYPE_FROM_CLASS (class),
- G_SIGNAL_RUN_LAST,
- 0,
- NULL, NULL,
- NULL,
- G_TYPE_NONE, 3,
- GDK_TYPE_DROP, G_TYPE_INT, G_TYPE_INT);
-
- /**
- * GtkWidget::accept:
- * @dest: the #GtkDropTarget
- * @drop: the #GdkDrop
- *
- * The ::accept signal is emitted on the drop site when the user
- * moves the cursor over the widget during a drag. The signal handler
- * must determine whether the cursor position is in a drop zone or not.
- * If it is not in a drop zone, it returns %FALSE and no further processing
- * is necessary. Otherwise, the handler returns %TRUE. In this case, the
- * handler is responsible for providing the necessary information for
- * displaying feedback to the user, by calling gdk_drag_status().
- *
- * The default handler for this signal decides whether to accept the drop
- * based on the type of the data.
- *
- * If the decision whether the drop will be accepted or rejected can't be
- * made based solely the data format, handler may inspect the dragged data
- * by calling one of the #GdkDrop read functions and return %TRUE to
- * tentatively accept the drop. When the data arrives and is found to not be
- * acceptable, a call to gtk_drop_target_deny_drop() should be made to reject
- * the drop.
- *
- * Returns: whether the cursor position is in a drop zone
- */
- signals[ACCEPT] =
- g_signal_new (I_("accept"),
- G_TYPE_FROM_CLASS (class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GtkDropTargetClass, accept),
- g_signal_accumulator_first_wins, NULL,
- NULL,
- G_TYPE_BOOLEAN, 1,
- GDK_TYPE_DROP);
-
- /**
- * GtkDropTarget::drag-drop:
- * @dest: the #GtkDropTarget
- * @drop: the #GdkDrop
- * @x: the x coordinate of the current cursor position
- * @y: the y coordinate of the current cursor position
- *
- * The ::drag-drop signal is emitted on the drop site when the user drops
- * the data onto the widget. The signal handler must determine whether
- * the cursor position is in a drop zone or not. If it is not in a drop
- * zone, it returns %FALSE and no further processing is necessary.
- *
- * Otherwise, the handler returns %TRUE. In this case, the handler must
- * ensure that gdk_drop_finish() is called to let the source know that
- * the drop is done. The call to gtk_drag_finish() can be done either
- * directly or after receiving the data.
- *
- * To receive the data, use one of the read functions provides by #GtkDrop
- * and #GtkDragDest: gdk_drop_read_async(), gdk_drop_read_value_async(),
- * gdk_drop_read_text_async().
- *
- * You can use gtk_drop_target_get_drop() to obtain the #GtkDrop object
- * for the ongoing operation in your signal handler. If you call one of the
- * read functions in your handler, GTK will ensure that the #GtkDrop object
- * stays alive until the read is completed. If you delay obtaining the data
- * (e.g. to handle %GDK_ACTION_ASK by showing a #GtkPopover), you need to
- * hold a reference on the #GtkDrop.
- *
- * Returns: whether the cursor position is in a drop zone
- */
- signals[DRAG_DROP] =
- g_signal_new (I_("drag-drop"),
- G_TYPE_FROM_CLASS (class),
- G_SIGNAL_RUN_LAST,
- 0,
- NULL, NULL,
- NULL,
- G_TYPE_BOOLEAN, 3,
- GDK_TYPE_DROP, G_TYPE_INT, G_TYPE_INT);
-}
-
-/**
- * gtk_drop_target_new:
- * @formats: (nullable) (transfer full): the supported data formats
- * @actions: the supported actions
- *
- * Creates a new #GtkDropTarget object.
- *
- * Returns: the new #GtkDropTarget
- */
-GtkDropTarget *
-gtk_drop_target_new (GdkContentFormats *formats,
- GdkDragAction actions)
-{
- GtkDropTarget *result;
-
- result = g_object_new (GTK_TYPE_DROP_TARGET,
- "formats", formats,
- "actions", actions,
- NULL);
-
- g_clear_pointer (&formats, gdk_content_formats_unref);
-
- return result;
-}
-
-/**
- * gtk_drop_target_set_formats:
- * @dest: a #GtkDropTarget
- * @formats: (nullable): the supported data formats
- *
- * Sets the data formats that this drop target will accept.
- */
-void
-gtk_drop_target_set_formats (GtkDropTarget *dest,
- GdkContentFormats *formats)
-{
- g_return_if_fail (GTK_IS_DROP_TARGET (dest));
-
- if (dest->formats == formats)
- return;
-
- if (dest->formats)
- gdk_content_formats_unref (dest->formats);
-
- dest->formats = formats;
-
- if (dest->formats)
- gdk_content_formats_ref (dest->formats);
-
- g_object_notify_by_pspec (G_OBJECT (dest), properties[PROP_FORMATS]);
-}
-
-/**
- * gtk_drop_target_get_formats:
- * @dest: a #GtkDropTarget
- *
- * Gets the data formats that this drop target accepts.
- *
- * If the result is %NULL, all formats are expected to be supported.
- *
- * Returns: (nullable): the supported data formats
- */
-GdkContentFormats *
-gtk_drop_target_get_formats (GtkDropTarget *dest)
-{
- g_return_val_if_fail (GTK_IS_DROP_TARGET (dest), NULL);
-
- return dest->formats;
-}
-
-/**
- * gtk_drop_target_set_actions:
- * @dest: a #GtkDropTarget
- * @actions: the supported actions
- *
- * Sets the actions that this drop target supports.
- */
-void
-gtk_drop_target_set_actions (GtkDropTarget *dest,
- GdkDragAction actions)
-{
- g_return_if_fail (GTK_IS_DROP_TARGET (dest));
-
- if (dest->actions == actions)
- return;
-
- dest->actions = actions;
-
- g_object_notify_by_pspec (G_OBJECT (dest), properties[PROP_ACTIONS]);
-}
-
-/**
- * gtk_drop_target_get_actions:
- * @dest: a #GtkDropTarget
- *
- * Gets the actions that this drop target supports.
- *
- * Returns: the actions that this drop target supports
- */
-GdkDragAction
-gtk_drop_target_get_actions (GtkDropTarget *dest)
-{
- g_return_val_if_fail (GTK_IS_DROP_TARGET (dest), 0);
-
- return dest->actions;
-}
-
-/**
- * gtk_drop_target_get_drop:
- * @dest: a #GtkDropTarget
- *
- * Returns the underlying #GtkDrop object for an ongoing drag.
- *
- * Returns: (nullable) (transfer none): the #GtkDrop of the current drag operation, or %NULL
- */
-GdkDrop *
-gtk_drop_target_get_drop (GtkDropTarget *dest)
-{
- g_return_val_if_fail (GTK_IS_DROP_TARGET (dest), NULL);
-
- return dest->drop;
-}
-
-static const char *
-gtk_drop_target_match (GtkDropTarget *dest,
- GdkDrop *drop)
-{
- GdkContentFormats *formats;
- const char *match;
-
- formats = gdk_content_formats_ref (dest->formats);
- formats = gdk_content_formats_union_deserialize_mime_types (formats);
-
- match = gdk_content_formats_match_mime_type (formats, gdk_drop_get_formats (drop));
-
- gdk_content_formats_unref (formats);
-
- return match;
-}
-
-/**
- * gtk_drop_target_find_mimetype:
- * @dest: a #GtkDropTarget
- *
- * Returns a mimetype that is supported both by @dest and the ongoing
- * drag. For more detailed control, you can use gdk_drop_get_formats()
- * to obtain the content formats that are supported by the source.
- *
- * Returns: (nullable): a matching mimetype for the ongoing drag, or %NULL
- */
-const char *
-gtk_drop_target_find_mimetype (GtkDropTarget *dest)
-{
- if (!dest->drop)
- return NULL;
-
- if (dest->formats == NULL)
- return NULL;
-
- return gtk_drop_target_match (dest, dest->drop);
-}
-
-static gboolean
-gtk_drop_target_accept (GtkDropTarget *dest,
- GdkDrop *drop)
-{
- if ((gdk_drop_get_actions (drop) & gtk_drop_target_get_actions (dest)) == 0)
- return FALSE;
-
- if (dest->formats == NULL)
- return TRUE;
-
- return gdk_content_formats_match (dest->formats, gdk_drop_get_formats (drop));
-}
-
-static void
-set_drop (GtkDropTarget *dest,
- GdkDrop *drop)
-{
- if (dest->drop == drop)
- return;
-
- if (dest->drop)
- g_object_remove_weak_pointer (G_OBJECT (dest->drop), (gpointer *)&dest->drop);
-
- dest->drop = drop;
-
- if (dest->drop)
- g_object_add_weak_pointer (G_OBJECT (dest->drop), (gpointer *)&dest->drop);
-}
-
-static void
-gtk_drop_target_emit_drag_enter (GtkDropTarget *dest,
- GdkDrop *drop)
-{
- set_drop (dest, drop);
- g_signal_emit (dest, signals[DRAG_ENTER], 0, drop);
-}
-
-static void
-gtk_drop_target_emit_drag_leave (GtkDropTarget *dest,
- GdkDrop *drop)
-{
- set_drop (dest, drop);
- g_signal_emit (dest, signals[DRAG_LEAVE], 0, drop);
- set_drop (dest, NULL);
-}
-
-static gboolean
-gtk_drop_target_emit_accept (GtkDropTarget *dest,
- GdkDrop *drop)
-{
- gboolean result = FALSE;
-
- set_drop (dest, drop);
- g_signal_emit (dest, signals[ACCEPT], 0, drop, &result);
-
- return result;
-}
-
-static void
-gtk_drop_target_emit_drag_motion (GtkDropTarget *dest,
- GdkDrop *drop,
- int x,
- int y)
-{
- set_drop (dest, drop);
- g_signal_emit (dest, signals[DRAG_MOTION], 0, drop, x, y);
-}
-
-static gboolean
-gtk_drop_target_emit_drag_drop (GtkDropTarget *dest,
- GdkDrop *drop,
- int x,
- int y)
-{
- gboolean result = FALSE;
-
- set_drop (dest, drop);
- g_signal_emit (dest, signals[DRAG_DROP], 0, drop, x, y, &result);
-
- return result;
-}
-
-static void
-gtk_drop_target_set_contains (GtkDropTarget *dest,
- gboolean contains)
-{
- if (dest->contains == contains)
- return;
-
- dest->contains = contains;
-
- g_object_notify_by_pspec (G_OBJECT (dest), properties[PROP_CONTAINS]);
-}
-
-static gboolean
-gtk_drop_target_get_contains (GtkDropTarget *dest)
-{
- return dest->contains;
-}
-
-static gboolean
-gtk_drop_target_filter_event (GtkEventController *controller,
- GdkEvent *event)
-{
- switch ((int)gdk_event_get_event_type (event))
- {
- case GDK_DRAG_ENTER:
- case GDK_DRAG_LEAVE:
- case GDK_DRAG_MOTION:
- case GDK_DROP_START:
- return GTK_EVENT_CONTROLLER_CLASS (gtk_drop_target_parent_class)->filter_event (controller, event);
-
- default:;
- }
-
- return TRUE;
-}
-
-static void
-clear_current_dest (gpointer data, GObject *former_object)
-{
- g_object_set_data (G_OBJECT (data), "current-dest", NULL);
-}
-
-static void
-unset_current_dest (gpointer data)
-{
- GtkDropTarget *dest = data;
- GtkWidget *widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (dest));
-
- gtk_drop_target_set_contains (dest, FALSE);
- if (widget)
- gtk_widget_unset_state_flags (widget, GTK_STATE_FLAG_DROP_ACTIVE);
-}
-
-static GtkDropTarget *
-gtk_drop_get_current_dest (GdkDrop *drop)
-{
- return GTK_DROP_TARGET (g_object_get_data (G_OBJECT (drop), "current-dest"));
-}
-
-static void
-gtk_drop_set_current_dest (GdkDrop *drop,
- GtkDropTarget *dest)
-{
- GtkDropTarget *old_dest;
- GtkWidget *widget;
-
- old_dest = g_object_get_data (G_OBJECT (drop), "current-dest");
-
- if (old_dest == dest)
- return;
-
- if (old_dest)
- {
- gtk_drop_target_set_contains (old_dest, FALSE);
-
- widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (old_dest));
- if (widget)
- gtk_widget_unset_state_flags (widget, GTK_STATE_FLAG_DROP_ACTIVE);
-
- gtk_drop_target_emit_drag_leave (old_dest, drop);
-
- g_object_weak_unref (G_OBJECT (old_dest), clear_current_dest, drop);
- }
-
- g_object_set_data_full (G_OBJECT (drop), "current-dest", dest, unset_current_dest);
-
- if (dest)
- {
- g_object_weak_ref (G_OBJECT (dest), clear_current_dest, drop);
-
- gtk_drop_target_emit_drag_enter (dest, drop);
-
- widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (dest));
- if (widget)
- gtk_widget_set_state_flags (widget, GTK_STATE_FLAG_DROP_ACTIVE, FALSE);
-
- gtk_drop_target_set_contains (dest, TRUE);
- }
-}
-
-static gboolean
-gtk_drop_target_handle_event (GtkEventController *controller,
- GdkEvent *event,
- double x,
- double y)
-{
- GtkDropTarget *dest = GTK_DROP_TARGET (controller);
- GdkDrop *drop;
- GtkDropStatus status;
- gboolean found = FALSE;
-
- drop = gdk_drag_event_get_drop (event);
-
- status = gtk_drop_target_get_drop_status (dest, drop);
- if (status == GTK_DROP_STATUS_DENIED)
- return FALSE;
-
- switch ((int)gdk_event_get_event_type (event))
- {
- case GDK_DRAG_MOTION:
- if (status != GTK_DROP_STATUS_ACCEPTED)
- {
- found = gtk_drop_target_emit_accept (dest, drop);
- if (found)
- gtk_drop_target_set_drop_status (dest, drop, GTK_DROP_STATUS_ACCEPTED);
- }
- else
- found = TRUE;
-
- if (found)
- {
- gdk_drop_status (drop, gtk_drop_target_get_actions (dest));
- gtk_drop_set_current_dest (drop, dest);
- gtk_drop_target_emit_drag_motion (dest, drop, x, y);
- }
- break;
-
- case GDK_DROP_START:
- found = gtk_drop_target_emit_drag_drop (dest, drop, x, y);
- break;
-
- default:
- break;
- }
-
- return found;
-}
-
-/*
- * This function is called if none of the event
- * controllers has handled a drag event.
- */
-void
-gtk_drag_dest_handle_event (GtkWidget *toplevel,
- GdkEvent *event)
-{
- GdkDrop *drop;
- GdkEventType event_type;
-
- g_return_if_fail (toplevel != NULL);
- g_return_if_fail (event != NULL);
-
- event_type = gdk_event_get_event_type (event);
- drop = gdk_drag_event_get_drop (event);
-
- switch ((guint) event_type)
- {
- case GDK_DRAG_LEAVE:
- gtk_drop_set_current_dest (drop, NULL);
- break;
-
- case GDK_DRAG_ENTER:
- case GDK_DRAG_MOTION:
- case GDK_DROP_START:
- gtk_drop_set_current_dest (drop, NULL);
- gdk_drop_status (drop, 0);
- break;
-
- default:
- g_assert_not_reached ();
- }
-}
-
-static GtkDropStatus
-gtk_drop_target_get_drop_status (GtkDropTarget *dest,
- GdkDrop *drop)
-{
- GHashTable *denied;
-
- denied = (GHashTable *)g_object_get_data (G_OBJECT (drop), "denied-drags");
- if (denied)
- return GPOINTER_TO_INT (g_hash_table_lookup (denied, dest));
-
- return GTK_DROP_STATUS_NONE;
-}
-
-static void
-gtk_drop_target_set_drop_status (GtkDropTarget *dest,
- GdkDrop *drop,
- GtkDropStatus status)
-{
- GHashTable *drags;
-
- drags = (GHashTable *)g_object_get_data (G_OBJECT (drop), "denied-drags");
- if (!drags)
- {
- drags = g_hash_table_new (NULL, NULL);
- g_object_set_data_full (G_OBJECT (drop), "denied-drags", drags, (GDestroyNotify)g_hash_table_unref);
- }
-
- g_hash_table_insert (drags, dest, GINT_TO_POINTER (status));
-
- if (dest == gtk_drop_get_current_dest (drop))
- {
- gdk_drop_status (drop, 0);
- gtk_drop_set_current_dest (drop, NULL);
- }
-}
-
-/**
- * gtk_drop_target_deny_drop:
- * @dest: a #GtkDropTarget
- * @drop: the #GdkDrop of an ongoing drag operation
- *
- * Sets the @drop as not accepted on this drag site.
- *
- * This function should be used when delaying the decision
- * on whether to accept a drag or not until after reading
- * the data.
- */
-void
-gtk_drop_target_deny_drop (GtkDropTarget *dest,
- GdkDrop *drop)
-{
- g_return_if_fail (GTK_IS_DROP_TARGET (dest));
- g_return_if_fail (GDK_IS_DROP (drop));
-
- gtk_drop_target_set_drop_status (dest, drop, GTK_DROP_STATUS_DENIED);
-}
+++ /dev/null
-/* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */
-/* GTK - The GIMP Toolkit
- * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
- * file for a list of people on the GTK+ Team. See the ChangeLog
- * files for a list of changes. These files are distributed with
- * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
- */
-
-#ifndef __GTK_DRAG_DEST_H__
-#define __GTK_DRAG_DEST_H__
-
-
-#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
-#error "Only <gtk/gtk.h> can be included directly."
-#endif
-
-#include <gtk/gtkwidget.h>
-
-
-G_BEGIN_DECLS
-
-typedef struct _GtkDropTarget GtkDropTarget;
-
-
-#define GTK_TYPE_DROP_TARGET (gtk_drop_target_get_type ())
-#define GTK_DROP_TARGET(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_DROP_TARGET, GtkDropTarget))
-#define GTK_DROP_TARGET_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GTK_TYPE_DROP_TARGET, GtkDropTargetClass))
-#define GTK_IS_DROP_TARGET(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_DROP_TARGET))
-#define GTK_IS_DROP_TARGET_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GTK_TYPE_DROP_TARGET))
-#define GTK_DROP_TARGET_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_DROP_TARGET, GtkDropTargetClass))
-
-typedef struct _GtkDropTargetClass GtkDropTargetClass;
-
-GDK_AVAILABLE_IN_ALL
-GType gtk_drop_target_get_type (void) G_GNUC_CONST;
-
-GDK_AVAILABLE_IN_ALL
-GtkDropTarget *gtk_drop_target_new (GdkContentFormats *formats,
- GdkDragAction actions);
-
-GDK_AVAILABLE_IN_ALL
-void gtk_drop_target_set_formats (GtkDropTarget *dest,
- GdkContentFormats *formats);
-GDK_AVAILABLE_IN_ALL
-GdkContentFormats *gtk_drop_target_get_formats (GtkDropTarget *dest);
-
-GDK_AVAILABLE_IN_ALL
-void gtk_drop_target_set_actions (GtkDropTarget *dest,
- GdkDragAction actions);
-GDK_AVAILABLE_IN_ALL
-GdkDragAction gtk_drop_target_get_actions (GtkDropTarget *dest);
-
-GDK_AVAILABLE_IN_ALL
-GdkDrop *gtk_drop_target_get_drop (GtkDropTarget *dest);
-
-GDK_AVAILABLE_IN_ALL
-const char *gtk_drop_target_find_mimetype (GtkDropTarget *dest);
-
-GDK_AVAILABLE_IN_ALL
-void gtk_drop_target_deny_drop (GtkDropTarget *dest,
- GdkDrop *drop);
-
-
-G_END_DECLS
-
-#endif /* __GTK_DRAG_DEST_H__ */
--- /dev/null
+/*
+ * Copyright © 2020 Benjamin Otte
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Benjamin Otte <otte@gnome.org>
+ */
+
+#include "config.h"
+
+#include "gtkdropprivate.h"
+
+typedef struct _GtkDrop GtkDrop;
+
+struct _GtkDrop
+{
+ /* TRUE if we are waiting for a gdk_drop_status() call */
+ gboolean waiting;
+ /* TRUE if begin_event() has been called but end_event() hasn't yet - purely for debugging */
+ gboolean active;
+};
+
+static void
+gtk_drop_free (gpointer data)
+{
+ GtkDrop *self = data;
+
+ g_slice_free (GtkDrop, self);
+}
+
+static GtkDrop *
+gtk_drop_lookup (GdkDrop *drop)
+{
+ static GQuark drop_quark = 0;
+ GtkDrop *result;
+
+ if (G_UNLIKELY (drop_quark == 0))
+ drop_quark = g_quark_from_string ("-gtk-drop-data");
+
+ result = g_object_get_qdata (G_OBJECT (drop), drop_quark);
+ if (result == NULL)
+ {
+ result = g_slice_new0 (GtkDrop);
+ g_object_set_qdata_full (G_OBJECT (drop), drop_quark, result, gtk_drop_free);
+ }
+
+ return result;
+}
+
+void
+gtk_drop_begin_event (GdkDrop *drop,
+ GdkEventType event_type)
+{
+ GtkDrop *self;
+
+ self = gtk_drop_lookup (drop);
+
+ g_assert (self->waiting == FALSE);
+ g_assert (self->active == FALSE);
+
+ self->active = TRUE;
+ if (event_type == GDK_DRAG_ENTER ||
+ event_type == GDK_DRAG_MOTION)
+ self->waiting = TRUE;
+}
+
+void
+gtk_drop_end_event (GdkDrop *drop)
+{
+ GtkDrop *self;
+
+ self = gtk_drop_lookup (drop);
+
+ g_assert (self->active == TRUE);
+
+ if (self->waiting)
+ {
+ gdk_drop_status (drop, 0);
+ self->waiting = FALSE;
+ }
+ self->active = FALSE;
+}
+
+gboolean
+gtk_drop_status (GdkDrop *drop,
+ GdkDragAction actions,
+ GdkDragAction preferred_action)
+{
+ GtkDrop *self;
+
+ self = gtk_drop_lookup (drop);
+
+ g_assert (self->active == TRUE);
+
+ if (!self->waiting)
+ return FALSE;
+
+ gdk_drop_status (drop, actions);
+ self->waiting = FALSE;
+ return TRUE;
+}
+
--- /dev/null
+/*
+ * Copyright © 2020 Benjamin Otte
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Benjamin Otte <otte@gnome.org>
+ */
+
+#ifndef __GTK_DROP_PRIVATE_H__
+#define __GTK_DROP_PRIVATE_H__
+
+#include <gdk/gdk.h>
+
+G_BEGIN_DECLS
+
+
+void gtk_drop_begin_event (GdkDrop *drop,
+ GdkEventType event_type);
+void gtk_drop_end_event (GdkDrop *drop);
+
+gboolean gtk_drop_status (GdkDrop *drop,
+ GdkDragAction actions,
+ GdkDragAction preferred_action);
+
+G_END_DECLS
+
+#endif
--- /dev/null
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1999 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GTK+ Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#include "config.h"
+
+#include "gtkdroptarget.h"
+
+#include "gtkdropprivate.h"
+#include "gtkeventcontrollerprivate.h"
+#include "gtkintl.h"
+#include "gtkmarshalers.h"
+#include "gtknative.h"
+#include "gtkprivate.h"
+#include "gtktypebuiltins.h"
+
+
+/**
+ * SECTION:gtkdroptarget
+ * @Short_description: Event controller to receive DND drops
+ * @Title: GtkDropTarget
+ * @See_also: #GdkDrop, #GtkDropTargetAsync
+ *
+ * GtkDropTarget is an event controller implementing a simple way to
+ * receive Drag-and-Drop operations.
+ *
+ * The most basic way to use a #GtkDropTarget to receive drops on a
+ * widget, is to create it via gtk_drop_target_new(), passing in the
+ * #GType of the data you want to receive and connect to the
+ * GtkDropTarget::drop signal to receive the data.
+ *
+ * #GtkDropTarget supports more options, such as:
+ *
+ * * rejecting potential drops via the GtkDropTarget::accept signal
+ * and the gtk_drop_target_reject() function to let other drop
+ * targets handle the drop
+ * * tracking an ongoing drag operation before the drop via the
+ * GtkDropTarget::enter, GtkDropTarget::motion and
+ * GtkDropTarget::leave signals
+ * * configuring how to receive data by setting the
+ * GtkDropTarget:preload property and listening for its availability
+ * via the GtkDropTarget:value property
+ *
+ * However, #GtkDropTarget is ultimately modeled in a synchronous way
+ * and only supports data transferred via #GType.
+ * If you want full control over an ongoing drop, the #GdkDropTargetAsync
+ * object gives you this ability.
+ *
+ * While a pointer is dragged over the drop target's widget and the drop
+ * has not been rejected, that widget will receive the
+ * %GTK_STATE_FLAG_DROP_ACTIVE state, which can be used to style the widget.
+ */
+
+struct _GtkDropTarget
+{
+ GtkEventController parent_object;
+
+ GdkContentFormats *formats;
+ GdkDragAction actions;
+ guint preload : 1;
+
+ guint dropping : 1;
+ graphene_point_t coords;
+ GdkDrop *drop;
+ GCancellable *cancellable; /* NULL unless doing a read of value */
+ GValue value;
+};
+
+struct _GtkDropTargetClass
+{
+ GtkEventControllerClass parent_class;
+
+ gboolean (* accept) (GtkDropTarget *self,
+ GdkDrop *drop);
+ GdkDragAction (* enter) (GtkDropTarget *self,
+ double x,
+ double y);
+ GdkDragAction (* motion) (GtkDropTarget *self,
+ double x,
+ double y);
+ void (* leave) (GtkDropTarget *self,
+ GdkDrop *drop);
+ gboolean (* drop) (GtkDropTarget *self,
+ const GValue *value,
+ double x,
+ double y);
+};
+
+enum {
+ PROP_0,
+ PROP_ACTIONS,
+ PROP_DROP,
+ PROP_FORMATS,
+ PROP_PRELOAD,
+ PROP_VALUE,
+ NUM_PROPERTIES
+};
+
+static GParamSpec *properties[NUM_PROPERTIES];
+
+enum {
+ ACCEPT,
+ ENTER,
+ MOTION,
+ LEAVE,
+ DROP,
+ NUM_SIGNALS
+};
+
+static guint signals[NUM_SIGNALS];
+
+G_DEFINE_TYPE (GtkDropTarget, gtk_drop_target, GTK_TYPE_EVENT_CONTROLLER);
+
+static void
+gtk_drop_target_end_drop (GtkDropTarget *self)
+{
+ if (self->drop == NULL)
+ return;
+
+ g_object_freeze_notify (G_OBJECT (self));
+
+ if (self->dropping)
+ {
+ gdk_drop_finish (self->drop, 0);
+ self->dropping = FALSE;
+ }
+
+ g_clear_object (&self->drop);
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DROP]);
+
+ if (G_IS_VALUE (&self->value))
+ {
+ g_value_unset (&self->value);
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_VALUE]);
+ }
+
+ if (self->cancellable)
+ {
+ g_cancellable_cancel (self->cancellable);
+ g_clear_object (&self->cancellable);
+ }
+
+ gtk_widget_unset_state_flags (gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (self)),
+ GTK_STATE_FLAG_DROP_ACTIVE);
+
+ g_object_thaw_notify (G_OBJECT (self));
+}
+
+static void
+gtk_drop_target_do_drop (GtkDropTarget *self)
+{
+ gboolean success;
+
+ g_assert (self->dropping);
+ g_assert (G_IS_VALUE (&self->value));
+
+ g_signal_emit (self, signals[DROP], 0, &self->value, self->coords.x, self->coords.y, &success);
+
+ if (success)
+ gdk_drop_finish (self->drop, gdk_drop_get_actions (self->drop));
+ else
+ gdk_drop_finish (self->drop, 0);
+
+ self->dropping = FALSE;
+
+ gtk_drop_target_end_drop (self);
+}
+
+static void
+gtk_drop_target_load_done (GObject *source,
+ GAsyncResult *res,
+ gpointer data)
+{
+ GtkDropTarget *self = data;
+ const GValue *value;
+ GError *error = NULL;
+
+ value = gdk_drop_read_value_finish (GDK_DROP (source), res, &error);
+ if (value == NULL)
+ {
+ /* If this happens, data/self is invalid */
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ {
+ g_clear_error (&error);
+ return;
+ }
+
+ g_clear_object (&self->cancellable);
+ /* XXX: Should this be a warning? */
+ g_warning ("Failed to receive drop data: %s", error->message);
+ g_clear_error (&error);
+ gtk_drop_target_end_drop (self);
+ return;
+ }
+
+ g_clear_object (&self->cancellable);
+ g_value_init (&self->value, G_VALUE_TYPE (value));
+ g_value_copy (value, &self->value);
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_VALUE]);
+
+ if (self->dropping)
+ gtk_drop_target_do_drop (self);
+}
+
+static gboolean
+gtk_drop_target_load (GtkDropTarget *self)
+{
+ g_assert (self->drop);
+
+ if (G_IS_VALUE (&self->value))
+ return TRUE;
+
+ if (self->cancellable)
+ return FALSE;
+
+ self->cancellable = g_cancellable_new ();
+
+ gdk_drop_read_value_async (self->drop,
+ gdk_content_formats_match_gtype (self->formats, gdk_drop_get_formats (self->drop)),
+ G_PRIORITY_DEFAULT,
+ self->cancellable,
+ gtk_drop_target_load_done,
+ g_object_ref (self));
+ return FALSE;
+}
+
+static void
+gtk_drop_target_start_drop (GtkDropTarget *self,
+ GdkDrop *drop)
+{
+ g_object_freeze_notify (G_OBJECT (self));
+
+ gtk_drop_target_end_drop (self);
+
+ self->drop = g_object_ref (drop);
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DROP]);
+
+ if (self->preload)
+ gtk_drop_target_load (self);
+
+ gtk_widget_set_state_flags (gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (self)),
+ GTK_STATE_FLAG_DROP_ACTIVE,
+ FALSE);
+
+ g_object_thaw_notify (G_OBJECT (self));
+}
+
+static gboolean
+gtk_drop_target_accept (GtkDropTarget *self,
+ GdkDrop *drop)
+{
+ if ((gdk_drop_get_actions (drop) & gtk_drop_target_get_actions (self)) == 0)
+ return FALSE;
+
+ if (self->formats == NULL)
+ return TRUE;
+
+ return gdk_content_formats_match (self->formats, gdk_drop_get_formats (drop));
+}
+
+static GdkDragAction
+make_action_unique (GdkDragAction actions)
+{
+ if (actions & GDK_ACTION_COPY)
+ return GDK_ACTION_COPY;
+
+ if (actions & GDK_ACTION_MOVE)
+ return GDK_ACTION_MOVE;
+
+ if (actions & GDK_ACTION_LINK)
+ return GDK_ACTION_LINK;
+
+ return 0;
+}
+
+static GdkDragAction
+gtk_drop_target_enter (GtkDropTarget *self,
+ double x,
+ double y)
+{
+ return make_action_unique (self->actions & gdk_drop_get_actions (self->drop));
+}
+
+static GdkDragAction
+gtk_drop_target_motion (GtkDropTarget *self,
+ double x,
+ double y)
+{
+ return make_action_unique (self->actions & gdk_drop_get_actions (self->drop));
+}
+
+static gboolean
+gtk_drop_target_drop (GtkDropTarget *self,
+ const GValue *value,
+ double x,
+ double y)
+{
+ return FALSE;
+}
+
+static gboolean
+gtk_drop_target_filter_event (GtkEventController *controller,
+ GdkEvent *event)
+{
+ switch ((int) gdk_event_get_event_type (event))
+ {
+ case GDK_DRAG_ENTER:
+ case GDK_DRAG_LEAVE:
+ case GDK_DRAG_MOTION:
+ case GDK_DROP_START:
+ return GTK_EVENT_CONTROLLER_CLASS (gtk_drop_target_parent_class)->filter_event (controller, event);
+
+ default:;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+gtk_drop_target_handle_event (GtkEventController *controller,
+ GdkEvent *event,
+ double x,
+ double y)
+{
+ GtkDropTarget *self = GTK_DROP_TARGET (controller);
+
+ /* All drops have been rejected. New drops only arrive via crossing
+ * events, so we can: */
+ if (self->drop == NULL)
+ return FALSE;
+
+ switch ((int) gdk_event_get_event_type (event))
+ {
+ case GDK_DRAG_MOTION:
+ {
+ GtkWidget *widget = gtk_event_controller_get_widget (controller);
+ GdkDragAction preferred;
+
+ /* sanity check */
+ g_return_val_if_fail (self->drop == gdk_drag_event_get_drop (event), FALSE);
+
+ graphene_point_init (&self->coords, x, y);
+ g_signal_emit (self, signals[MOTION], 0, x, y, &preferred);
+ if (preferred &&
+ gtk_drop_status (self->drop, self->actions, preferred))
+ {
+ gtk_widget_set_state_flags (widget, GTK_STATE_FLAG_DROP_ACTIVE, FALSE);
+ }
+ else
+ {
+ gtk_widget_unset_state_flags (widget, GTK_STATE_FLAG_DROP_ACTIVE);
+ }
+ }
+ return FALSE;
+
+ case GDK_DROP_START:
+ {
+ /* sanity check */
+ g_return_val_if_fail (self->drop == gdk_drag_event_get_drop (event), FALSE);
+
+ graphene_point_init (&self->coords, x, y);
+ self->dropping = TRUE;
+ if (gtk_drop_target_load (self))
+ gtk_drop_target_do_drop (self);
+
+ return TRUE;
+ }
+
+ default:
+ return FALSE;
+ }
+}
+
+static void
+gtk_drop_target_handle_crossing (GtkEventController *controller,
+ const GtkCrossingData *crossing,
+ double x,
+ double y)
+{
+ GtkDropTarget *self = GTK_DROP_TARGET (controller);
+ GtkWidget *widget = gtk_event_controller_get_widget (controller);
+
+ if (crossing->type != GTK_CROSSING_DROP)
+ return;
+
+ /* sanity check */
+ g_warn_if_fail (self->drop == NULL || self->drop == crossing->drop);
+
+ if (crossing->direction == GTK_CROSSING_IN)
+ {
+ gboolean accept = FALSE;
+ GdkDragAction preferred;
+
+ if (self->drop != NULL)
+ return;
+
+ /* if we were a target already but self->drop == NULL, the drop
+ * was rejected already */
+ if (crossing->old_descendent != NULL ||
+ crossing->old_target == widget)
+ return;
+
+ g_signal_emit (self, signals[ACCEPT], 0, crossing->drop, &accept);
+ if (!accept)
+ return;
+
+ graphene_point_init (&self->coords, x, y);
+ gtk_drop_target_start_drop (self, crossing->drop);
+
+ g_signal_emit (self, signals[ENTER], 0, x, y, &preferred);
+ if (preferred &&
+ gtk_drop_status (self->drop, self->actions, preferred))
+ {
+ gtk_widget_set_state_flags (widget, GTK_STATE_FLAG_DROP_ACTIVE, FALSE);
+ }
+ else
+ {
+ gtk_widget_unset_state_flags (widget, GTK_STATE_FLAG_DROP_ACTIVE);
+ }
+ }
+ else
+ {
+ if (crossing->new_descendent != NULL ||
+ crossing->new_target == widget)
+ return;
+
+ g_signal_emit (self, signals[LEAVE], 0, self->drop);
+ if (!self->dropping)
+ gtk_drop_target_end_drop (self);
+ gtk_widget_unset_state_flags (widget, GTK_STATE_FLAG_DROP_ACTIVE);
+ }
+}
+
+static void
+gtk_drop_target_finalize (GObject *object)
+{
+ GtkDropTarget *self = GTK_DROP_TARGET (object);
+
+ g_clear_pointer (&self->formats, gdk_content_formats_unref);
+
+ G_OBJECT_CLASS (gtk_drop_target_parent_class)->finalize (object);
+}
+
+static void
+gtk_drop_target_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GtkDropTarget *self = GTK_DROP_TARGET (object);
+
+ switch (prop_id)
+ {
+ case PROP_ACTIONS:
+ gtk_drop_target_set_actions (self, g_value_get_flags (value));
+ break;
+
+ case PROP_PRELOAD:
+ gtk_drop_target_set_preload (self, g_value_get_boolean (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+gtk_drop_target_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GtkDropTarget *self = GTK_DROP_TARGET (object);
+
+ switch (prop_id)
+ {
+ case PROP_ACTIONS:
+ g_value_set_flags (value, self->actions);
+ break;
+
+ case PROP_DROP:
+ g_value_set_object (value, self->drop);
+ break;
+
+ case PROP_FORMATS:
+ g_value_set_boxed (value, self->formats);
+ break;
+
+ case PROP_PRELOAD:
+ g_value_set_boolean (value, self->preload);
+ break;
+
+ case PROP_VALUE:
+ if (G_IS_VALUE (&self->value))
+ g_value_set_boxed (value, &self->value);
+ else
+ g_value_set_boxed (value, NULL);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+gtk_drop_target_class_init (GtkDropTargetClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+ GtkEventControllerClass *controller_class = GTK_EVENT_CONTROLLER_CLASS (class);
+
+ object_class->finalize = gtk_drop_target_finalize;
+ object_class->set_property = gtk_drop_target_set_property;
+ object_class->get_property = gtk_drop_target_get_property;
+
+ controller_class->handle_event = gtk_drop_target_handle_event;
+ controller_class->filter_event = gtk_drop_target_filter_event;
+ controller_class->handle_crossing = gtk_drop_target_handle_crossing;
+
+ class->accept = gtk_drop_target_accept;
+ class->enter = gtk_drop_target_enter;
+ class->motion = gtk_drop_target_motion;
+ class->drop = gtk_drop_target_drop;
+
+ /**
+ * GtkDropTarget:actions:
+ *
+ * The #GdkDragActions that this drop target supports
+ */
+ properties[PROP_ACTIONS] =
+ g_param_spec_flags ("actions",
+ P_("Actions"),
+ P_("The actions supported by this drop target"),
+ GDK_TYPE_DRAG_ACTION, 0,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
+
+ /**
+ * GtkDropTarget:drop:
+ *
+ * The #GdkDrop that is currently being performed
+ */
+ properties[PROP_DROP] =
+ g_param_spec_object ("drop",
+ P_("Drop"),
+ P_("Current drop"),
+ GDK_TYPE_DROP,
+ GTK_PARAM_READABLE);
+
+ /**
+ * GtkDropTarget:formats:
+ *
+ * The #GdkContentFormats that determine the supported data formats
+ */
+ properties[PROP_FORMATS] =
+ g_param_spec_boxed ("formats",
+ P_("Formats"),
+ P_("The supported formats"),
+ GDK_TYPE_CONTENT_FORMATS,
+ GTK_PARAM_READABLE);
+
+ /**
+ * GtkDropTarget:preload:
+ *
+ * Whether the drop data should be preloaded when the pointer is only
+ * hovering over the widget but has not been released.
+ *
+ * Setting this property allows finer grained reaction to an ongoing
+ * drop at the cost of loading more data.
+ *
+ * The default value for this property is %FALSE to avoid downloading
+ * huge amounts of data by accident.
+ * For example, if somebody drags a full document of gigabytes of text
+ * from a text editor across a widget with a preloading drop target,
+ * this data will be downlaoded, even if the data is ultimately dropped
+ * elsewhere.
+ *
+ * For a lot of data formats, the amount of data is very small (like
+ * %GDK_TYPE_RGBA), so enabling this property does not hurt at all.
+ */
+ properties[PROP_PRELOAD] =
+ g_param_spec_boolean ("preload",
+ P_("Preload"),
+ P_("Whether drop data should be preloaded while hovering"),
+ FALSE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
+
+ /**
+ * GtkDropTarget:value:
+ *
+ * The value for this drop operation or %NULL if the data has not been
+ * loaded yet or no drop operation is going on.
+ *
+ * Data may be available before the GtkDropTarget::drop signal gets emitted -
+ * for example when the GtkDropTarget:preload property is set.
+ * You can use the GObject::notify signal to be notified of available data.
+ */
+ properties[PROP_VALUE] =
+ g_param_spec_boxed ("value",
+ P_("Value"),
+ P_("The value for this drop operation"),
+ G_TYPE_VALUE,
+ GTK_PARAM_READABLE);
+
+ g_object_class_install_properties (object_class, NUM_PROPERTIES, properties);
+
+ /**
+ * GtkDropTarget::accept:
+ * @self: the #GtkDropTarget
+ * @drop: the #GdkDrop
+ *
+ * The ::accept signal is emitted on the drop site when a drop operation
+ * is about to begin.
+ * If the drop is not accepted, %FALSE will be returned and the drop target
+ * will ignore the drop. If %TRUE is returned, the drop is accepted for now
+ * but may be rejected later via a call to gtk_drop_target_reject() or
+ * ultimately by returning %FALSE from GtkDropTarget::drop
+ *
+ * The default handler for this signal decides whether to accept the drop
+ * based on the formats provided by the @drop.
+ *
+ * If the decision whether the drop will be accepted or rejected needs
+ * inspecting the data, this function should return %TRUE, the
+ * GtkDropTarget:preload property should be set and the value
+ * should be inspected via the GObject::notify:value signal and then call
+ * gtk_drop_target_reject().
+ *
+ * Returns: %TRUE if @drop is accepted
+ */
+ signals[ACCEPT] =
+ g_signal_new (I_("accept"),
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GtkDropTargetClass, accept),
+ g_signal_accumulator_first_wins, NULL,
+ NULL,
+ G_TYPE_BOOLEAN, 1,
+ GDK_TYPE_DROP);
+
+ /**
+ * GtkDropTarget::enter:
+ * @self: the #GtkDropTarget
+ * @x: the x coordinate of the current pointer position
+ * @y: the y coordinate of the current pointer position
+ *
+ * The ::enter signal is emitted on the drop site when the pointer
+ * enters the widget. It can be used to set up custom highlighting.
+ *
+ * Returns: Preferred action for this drag operation or 0 if dropping is not
+ * supported at the current @x,@y location.
+ */
+ signals[ENTER] =
+ g_signal_new (I_("enter"),
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GtkDropTargetClass, enter),
+ g_signal_accumulator_first_wins, NULL,
+ NULL,
+ GDK_TYPE_DRAG_ACTION, 2,
+ G_TYPE_DOUBLE, G_TYPE_DOUBLE);
+
+ /**
+ * GtkDropTarget::motion:
+ * @self: the #GtkDropTarget
+ * @x: the x coordinate of the current pointer position
+ * @y: the y coordinate of the current pointer position
+ *
+ * The ::motion signal is emitted while the pointer is moving
+ * over the drop target.
+ *
+ * Returns: Preferred action for this drag operation or 0 if dropping is not
+ * supported at the current @x,@y location.
+ */
+ signals[MOTION] =
+ g_signal_new (I_("motion"),
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GtkDropTargetClass, motion),
+ g_signal_accumulator_first_wins, NULL,
+ NULL,
+ GDK_TYPE_DRAG_ACTION, 2,
+ G_TYPE_DOUBLE, G_TYPE_DOUBLE);
+
+ /**
+ * GtkDropTarget::leave:
+ * @self: the #GtkDropTarget
+ * @drop: the #GdkDrop
+ *
+ * The ::leave signal is emitted on the drop site when the pointer
+ * leaves the widget. Its main purpose it to undo things done in
+ * #GtkDropTarget::enter.
+ */
+ signals[LEAVE] =
+ g_signal_new (I_("leave"),
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GtkDropTargetClass, leave),
+ NULL, NULL,
+ NULL,
+ G_TYPE_NONE, 0);
+
+ /**
+ * GtkDropTarget::drop:
+ * @self: the #GtkDropTarget
+ * @value: the #GValue being dropped
+ * @x: the x coordinate of the current pointer position
+ * @y: the y coordinate of the current pointer position
+ *
+ * The ::drop signal is emitted on the drop site when the user drops
+ * the data onto the widget. The signal handler must determine whether
+ * the pointer position is in a drop zone or not. If it is not in a drop
+ * zone, it returns %FALSE and no further processing is necessary.
+ *
+ * Otherwise, the handler returns %TRUE. In this case, this handler will
+ * accept the drop. The handler is responsible for rading the given @value
+ * and performing the drop operation.
+ *
+ * Returns: whether the drop was accepted at the given pointer position
+ */
+ signals[DROP] =
+ g_signal_new (I_("drop"),
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ g_signal_accumulator_first_wins, NULL,
+ NULL,
+ G_TYPE_BOOLEAN, 3,
+ G_TYPE_VALUE, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
+}
+
+static void
+gtk_drop_target_init (GtkDropTarget *self)
+{
+ self->formats = gdk_content_formats_new (NULL, 0);
+}
+
+/**
+ * gtk_drop_target_new:
+ * @type: The supported type or %G_TYPE_INVALID
+ * @actions: the supported actions
+ *
+ * Creates a new #GtkDropTarget object.
+ *
+ * If the drop target should support more than 1 type, pass
+ * %G_TYPE_INVALID for @type and then call
+ * gtk_drop_target_set_gtypes().
+ *
+ * Returns: the new #GtkDropTarget
+ */
+GtkDropTarget *
+gtk_drop_target_new (GType type,
+ GdkDragAction actions)
+{
+ GtkDropTarget *result;
+
+ result = g_object_new (GTK_TYPE_DROP_TARGET,
+ "actions", actions,
+ NULL);
+
+ if (type != G_TYPE_INVALID)
+ gtk_drop_target_set_gtypes (result, &type, 1);
+
+ return result;
+}
+
+/**
+ * gtk_drop_target_get_formats:
+ * @self: a #GtkDropTarget
+ *
+ * Gets the data formats that this drop target accepts.
+ *
+ * If the result is %NULL, all formats are expected to be supported.
+ *
+ * Returns: (nullable): the supported data formats
+ */
+GdkContentFormats *
+gtk_drop_target_get_formats (GtkDropTarget *self)
+{
+ g_return_val_if_fail (GTK_IS_DROP_TARGET (self), NULL);
+
+ return self->formats;
+}
+
+/**
+ * gtk_drop_target_set_gtypes:
+ * @self: a #GtkDropTarget
+ * @types: (nullable) (transfer none) (array length=n_types):
+ * all supported #GTypes that can be dropped
+ * @n_types: number of @types
+ *
+ * Sets the supported #GTypes for this drop target.
+ *
+ * The GtkDropTarget::drop signal will
+ **/
+void
+gtk_drop_target_set_gtypes (GtkDropTarget *self,
+ GType *types,
+ gsize n_types)
+{
+ GdkContentFormatsBuilder *builder;
+ gsize i;
+
+ g_return_if_fail (GTK_IS_DROP_TARGET (self));
+ g_return_if_fail (n_types == 0 || types != NULL);
+
+ gdk_content_formats_unref (self->formats);
+
+ builder = gdk_content_formats_builder_new ();
+ for (i = 0; i < n_types; i++)
+ gdk_content_formats_builder_add_gtype (builder, types[i]);
+
+ self->formats = gdk_content_formats_builder_free_to_formats (builder);
+
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FORMATS]);
+}
+
+/**
+ * gtk_drop_target_get_gtypes:
+ * @self: a #GtkDropTarget
+ * @n_gtypes: (out) (allow-none): optional pointer to take the
+ * number of #GTypes contained in the return value
+ *
+ * Gets the list of supported #GTypes for @self. If no type have been set,
+ * %NULL will be returned.
+ *
+ * Returns: (transfer none) (nullable): %G_TYPE_INVALID-terminated array of
+ * types included in @formats or %NULL if none.
+ **/
+const GType *
+gtk_drop_target_get_gtypes (GtkDropTarget *self,
+ gsize *n_types)
+{
+ g_return_val_if_fail (GTK_IS_DROP_TARGET (self), NULL);
+
+ return gdk_content_formats_get_gtypes (self->formats, n_types);
+}
+
+/**
+ * gtk_drop_target_set_actions:
+ * @self: a #GtkDropTarget
+ * @actions: the supported actions
+ *
+ * Sets the actions that this drop target supports.
+ */
+void
+gtk_drop_target_set_actions (GtkDropTarget *self,
+ GdkDragAction actions)
+{
+ g_return_if_fail (GTK_IS_DROP_TARGET (self));
+
+ if (self->actions == actions)
+ return;
+
+ self->actions = actions;
+
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ACTIONS]);
+}
+
+/**
+ * gtk_drop_target_get_actions:
+ * @self: a #GtkDropTarget
+ *
+ * Gets the actions that this drop target supports.
+ *
+ * Returns: the actions that this drop target supports
+ */
+GdkDragAction
+gtk_drop_target_get_actions (GtkDropTarget *self)
+{
+ g_return_val_if_fail (GTK_IS_DROP_TARGET (self), 0);
+
+ return self->actions;
+}
+
+/**
+ * gtk_drop_target_set_preload:
+ * @self: a #GtkDropTarget
+ * @preload: %TRUE to preload drop data
+ *
+ * Sets the GtkDropTarget:preload property.
+ **/
+void
+gtk_drop_target_set_preload (GtkDropTarget *self,
+ gboolean preload)
+{
+ g_return_if_fail (GTK_IS_DROP_TARGET (self));
+
+ if (self->preload == preload)
+ return;
+
+ self->preload = preload;
+
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_PRELOAD]);
+}
+
+/**
+ * gtk_drop_target_get_preload:
+ * @self: a #GtkDropTarget
+ *
+ * Gets the value of the GtkDropTarget:preload property.
+ *
+ * Returns: %TRUE if drop data should be preloaded
+ */
+gboolean
+gtk_drop_target_get_preload (GtkDropTarget *self)
+{
+ g_return_val_if_fail (GTK_IS_DROP_TARGET (self), 0);
+
+ return self->preload;
+}
+
+/**
+ * gtk_drop_target_get_drop:
+ * @self: a #GtkDropTarget
+ *
+ * Gets the currently handled drop operation.
+ *
+ * If no drop operation is going on, %NULL is returned.
+ *
+ * Returns: (nullable) (transfer none): The current drop
+ **/
+GdkDrop *
+gtk_drop_target_get_drop (GtkDropTarget *self)
+{
+ g_return_val_if_fail (GTK_IS_DROP_TARGET (self), NULL);
+
+ return self->drop;
+}
+
+/**
+ * gtk_drop_target_get_value:
+ * @self: a #GtkDropTarget
+ *
+ * Gets the value of the GtkDropTarget:value porperty.
+ *
+ * Returns: (nullable) (transfer none): The current drop data
+ **/
+const GValue *
+gtk_drop_target_get_value (GtkDropTarget *self)
+{
+ g_return_val_if_fail (GTK_IS_DROP_TARGET (self), NULL);
+
+ if (!G_IS_VALUE (&self->value))
+ return NULL;
+
+ return &self->value;
+}
+
+/**
+ * gtk_drop_target_reject:
+ * @self: a #GtkDropTarget
+ *
+ * Rejects the ongoing drop operation.
+ *
+ * If no drop operation is ongoing - when GdkDropTarget:drop
+ * returns %NULL - this function does nothing.
+ *
+ * This function should be used when delaying the decision
+ * on whether to accept a drag or not until after reading
+ * the data.
+ */
+void
+gtk_drop_target_reject (GtkDropTarget *self)
+{
+ g_return_if_fail (GTK_IS_DROP_TARGET (self));
+
+ if (self->drop == NULL)
+ return;
+
+ gtk_drop_target_end_drop (self);
+}
+
--- /dev/null
+/*
+ * Copyright © 2020 Benjamin Otte
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Benjamin Otte <otte@gnome.org>
+ */
+
+#ifndef __GTK_DROP_TARGET_H__
+#define __GTK_DROP_TARGET_H__
+
+
+#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gtk/gtk.h> can be included directly."
+#endif
+
+#include <gtk/gtktypes.h>
+
+
+G_BEGIN_DECLS
+
+typedef struct _GtkDropTarget GtkDropTarget;
+
+
+#define GTK_TYPE_DROP_TARGET (gtk_drop_target_get_type ())
+#define GTK_DROP_TARGET(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_DROP_TARGET, GtkDropTarget))
+#define GTK_DROP_TARGET_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GTK_TYPE_DROP_TARGET, GtkDropTargetClass))
+#define GTK_IS_DROP_TARGET(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_DROP_TARGET))
+#define GTK_IS_DROP_TARGET_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GTK_TYPE_DROP_TARGET))
+#define GTK_DROP_TARGET_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_DROP_TARGET, GtkDropTargetClass))
+
+typedef struct _GtkDropTargetClass GtkDropTargetClass;
+
+GDK_AVAILABLE_IN_ALL
+GType gtk_drop_target_get_type (void) G_GNUC_CONST;
+
+GDK_AVAILABLE_IN_ALL
+GtkDropTarget * gtk_drop_target_new (GType type,
+ GdkDragAction actions);
+
+GDK_AVAILABLE_IN_ALL
+void gtk_drop_target_set_gtypes (GtkDropTarget *self,
+ GType *types,
+ gsize n_types);
+GDK_AVAILABLE_IN_ALL
+const GType * gtk_drop_target_get_gtypes (GtkDropTarget *self,
+ gsize *n_types);
+GDK_AVAILABLE_IN_ALL
+GdkContentFormats * gtk_drop_target_get_formats (GtkDropTarget *self);
+
+GDK_AVAILABLE_IN_ALL
+void gtk_drop_target_set_actions (GtkDropTarget *self,
+ GdkDragAction actions);
+GDK_AVAILABLE_IN_ALL
+GdkDragAction gtk_drop_target_get_actions (GtkDropTarget *self);
+
+GDK_AVAILABLE_IN_ALL
+void gtk_drop_target_set_preload (GtkDropTarget *self,
+ gboolean preload);
+GDK_AVAILABLE_IN_ALL
+gboolean gtk_drop_target_get_preload (GtkDropTarget *self);
+
+GDK_AVAILABLE_IN_ALL
+GdkDrop * gtk_drop_target_get_drop (GtkDropTarget *self);
+
+GDK_AVAILABLE_IN_ALL
+const GValue * gtk_drop_target_get_value (GtkDropTarget *self);
+
+GDK_AVAILABLE_IN_ALL
+void gtk_drop_target_reject (GtkDropTarget *self);
+
+
+G_END_DECLS
+
+#endif /* __GTK_DROP_TARGET_H__ */
--- /dev/null
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1999 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GTK+ Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#include "config.h"
+
+#include "gtkdroptargetasync.h"
+
+#include "gtkdropprivate.h"
+#include "gtkeventcontrollerprivate.h"
+#include "gtkintl.h"
+#include "gtkmarshalers.h"
+#include "gtknative.h"
+#include "gtktypebuiltins.h"
+
+
+/**
+ * SECTION:gtkdroptargetasync
+ * @Short_description: Event controller to receive DND drops
+ * @Title: GtkDropTargetAsync
+ * @See_also: #GtkDropTarget
+ *
+ * GtkDropTargetAsync is an auxiliary object that can be used to receive
+ * Drag-and-Drop operations.
+ * It is the more complete but also more complex method of handling drop
+ * operations compared to #GtkDropTarget and you should only use it if
+ * #GtkDropTarget doesn't provide all the features you need.
+ *
+ * To use a #GtkDropTargetAsync to receive drops on a widget, you create
+ * a #GtkDropTargetAsync object, configure which data formats and actions
+ * you support, connect to its signals, and then attach
+ * it to the widget with gtk_widget_add_controller().
+ *
+ * During a drag operation, the first signal that a GtkDropTargetAsync
+ * emits is #GtkDropTargetAsync::accept, which is meant to determine
+ * whether the target is a possible drop site for the ongoing drop.
+ * The default handler for the ::accept signal accepts the drop
+ * if it finds a compatible data format and an action that is supported
+ * on both sides.
+ *
+ * If it is, and the widget becomes a target, you will receive a
+ * #GtkDropTargetAsync::drag-enter signal, followed by
+ * #GtkDropTargetAsync::drag-motion signals as the pointer moves,
+ * optionally a #GtkDropTargetAsync::drop signal when a drop happens,
+ * and finally a #GtkDropTargetAsync::drag-leave signal when the pointer
+ * moves off the widget.
+ *
+ * The ::drag-enter and ::drag-motion handler return a #GdkDragAction
+ * to update the status of the ongoing operation. The ::drop handler
+ * should decide if it ultimately accepts the drop and if it does, it
+ * should initiate the data transfer and finish the operation by calling
+ * gdk_drop_finish().
+ *
+ * Between the ::drag-enter and ::drag-leave signals the widget is a
+ * current drop target, and will receive the %GTK_STATE_FLAG_DROP_ACTIVE
+ * state, which can be used by themes to style the widget as a drop target.
+ */
+
+struct _GtkDropTargetAsync
+{
+ GtkEventController parent_object;
+
+ GdkContentFormats *formats;
+ GdkDragAction actions;
+
+ GdkDrop *drop;
+ gboolean rejected;
+};
+
+struct _GtkDropTargetAsyncClass
+{
+ GtkEventControllerClass parent_class;
+
+ gboolean (* accept) (GtkDropTargetAsync *self,
+ GdkDrop *drop);
+ GdkDragAction (* drag_enter) (GtkDropTargetAsync *self,
+ GdkDrop *drop,
+ double x,
+ double y);
+ GdkDragAction (* drag_motion) (GtkDropTargetAsync *self,
+ GdkDrop *drop,
+ double x,
+ double y);
+ void (* drag_leave) (GtkDropTargetAsync *self,
+ GdkDrop *drop);
+ gboolean (* drop) (GtkDropTargetAsync *self,
+ GdkDrop *drop,
+ double x,
+ double y);
+};
+
+enum {
+ PROP_0,
+ PROP_ACTIONS,
+ PROP_FORMATS,
+ NUM_PROPERTIES
+};
+
+static GParamSpec *properties[NUM_PROPERTIES];
+
+enum {
+ ACCEPT,
+ DRAG_ENTER,
+ DRAG_MOTION,
+ DRAG_LEAVE,
+ DROP,
+ NUM_SIGNALS
+};
+
+static guint signals[NUM_SIGNALS];
+
+G_DEFINE_TYPE (GtkDropTargetAsync, gtk_drop_target_async, GTK_TYPE_EVENT_CONTROLLER);
+
+static gboolean
+gtk_drop_target_async_accept (GtkDropTargetAsync *self,
+ GdkDrop *drop)
+{
+ if ((gdk_drop_get_actions (drop) & self->actions) == 0)
+ return FALSE;
+
+ if (self->formats == NULL)
+ return TRUE;
+
+ return gdk_content_formats_match (self->formats, gdk_drop_get_formats (drop));
+}
+
+static GdkDragAction
+make_action_unique (GdkDragAction actions)
+{
+ if (actions & GDK_ACTION_COPY)
+ return GDK_ACTION_COPY;
+
+ if (actions & GDK_ACTION_MOVE)
+ return GDK_ACTION_MOVE;
+
+ if (actions & GDK_ACTION_LINK)
+ return GDK_ACTION_LINK;
+
+ return 0;
+}
+
+static GdkDragAction
+gtk_drop_target_async_drag_enter (GtkDropTargetAsync *self,
+ GdkDrop *drop,
+ double x,
+ double y)
+{
+ return make_action_unique (self->actions & gdk_drop_get_actions (drop));
+}
+
+static GdkDragAction
+gtk_drop_target_async_drag_motion (GtkDropTargetAsync *self,
+ GdkDrop *drop,
+ double x,
+ double y)
+{
+ return make_action_unique (self->actions & gdk_drop_get_actions (drop));
+}
+
+static gboolean
+gtk_drop_target_async_drop (GtkDropTargetAsync *self,
+ GdkDrop *drop,
+ double x,
+ double y)
+{
+ return FALSE;
+}
+
+static gboolean
+gtk_drop_target_async_filter_event (GtkEventController *controller,
+ GdkEvent *event)
+{
+ switch ((int)gdk_event_get_event_type (event))
+ {
+ case GDK_DRAG_ENTER:
+ case GDK_DRAG_LEAVE:
+ case GDK_DRAG_MOTION:
+ case GDK_DROP_START:
+ return GTK_EVENT_CONTROLLER_CLASS (gtk_drop_target_async_parent_class)->filter_event (controller, event);
+
+ default:;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+gtk_drop_target_async_handle_event (GtkEventController *controller,
+ GdkEvent *event,
+ double x,
+ double y)
+{
+ GtkDropTargetAsync *self = GTK_DROP_TARGET_ASYNC (controller);
+ GdkDrop *drop;
+
+ switch ((int) gdk_event_get_event_type (event))
+ {
+ case GDK_DRAG_MOTION:
+ {
+ GtkWidget *widget = gtk_event_controller_get_widget (controller);
+ GdkDragAction preferred_action;
+
+ drop = gdk_drag_event_get_drop (event);
+ /* sanity check */
+ g_return_val_if_fail (self->drop == drop, FALSE);
+ if (self->rejected)
+ return FALSE;
+
+ g_signal_emit (self, signals[DRAG_MOTION], 0, drop, x, y, &preferred_action);
+ if (preferred_action &&
+ gtk_drop_status (self->drop, self->actions, preferred_action))
+ {
+ gtk_widget_set_state_flags (widget, GTK_STATE_FLAG_DROP_ACTIVE, FALSE);
+ }
+ else
+ {
+ gtk_widget_unset_state_flags (widget, GTK_STATE_FLAG_DROP_ACTIVE);
+ }
+ }
+ return FALSE;
+
+ case GDK_DROP_START:
+ {
+ gboolean handled;
+
+ drop = gdk_drag_event_get_drop (event);
+ /* sanity check */
+ g_return_val_if_fail (self->drop == drop, FALSE);
+ if (self->rejected)
+ return FALSE;
+
+ g_signal_emit (self, signals[DROP], 0, self->drop, x, y, &handled);
+ return handled;
+ }
+
+ default:
+ return FALSE;
+ }
+}
+
+static void
+gtk_drop_target_async_handle_crossing (GtkEventController *controller,
+ const GtkCrossingData *crossing,
+ double x,
+ double y)
+{
+ GtkDropTargetAsync *self = GTK_DROP_TARGET_ASYNC (controller);
+ GtkWidget *widget = gtk_event_controller_get_widget (controller);
+
+ if (crossing->type != GTK_CROSSING_DROP)
+ return;
+
+ /* sanity check */
+ g_warn_if_fail (self->drop == NULL || self->drop == crossing->drop);
+
+ if (crossing->direction == GTK_CROSSING_IN)
+ {
+ gboolean accept = FALSE;
+ GdkDragAction preferred_action;
+
+ if (self->drop != NULL)
+ return;
+
+ self->drop = g_object_ref (crossing->drop);
+
+ g_signal_emit (self, signals[ACCEPT], 0, self->drop, &accept);
+ self->rejected = !accept;
+ if (self->rejected)
+ return;
+
+ g_signal_emit (self, signals[DRAG_ENTER], 0, self->drop, x, y, &preferred_action);
+ if (preferred_action &&
+ gtk_drop_status (self->drop, self->actions, preferred_action))
+ {
+ gtk_widget_set_state_flags (widget, GTK_STATE_FLAG_DROP_ACTIVE, FALSE);
+ }
+ }
+ else
+ {
+ if (crossing->new_descendent != NULL ||
+ crossing->new_target == widget)
+ return;
+
+ g_signal_emit (self, signals[DRAG_LEAVE], 0, self->drop);
+ g_clear_object (&self->drop);
+ gtk_widget_unset_state_flags (widget, GTK_STATE_FLAG_DROP_ACTIVE);
+ }
+}
+
+static void
+gtk_drop_target_async_finalize (GObject *object)
+{
+ GtkDropTargetAsync *self = GTK_DROP_TARGET_ASYNC (object);
+
+ g_clear_pointer (&self->formats, gdk_content_formats_unref);
+
+ G_OBJECT_CLASS (gtk_drop_target_async_parent_class)->finalize (object);
+}
+
+static void
+gtk_drop_target_async_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GtkDropTargetAsync *self = GTK_DROP_TARGET_ASYNC (object);
+
+ switch (prop_id)
+ {
+ case PROP_ACTIONS:
+ gtk_drop_target_async_set_actions (self, g_value_get_flags (value));
+ break;
+
+ case PROP_FORMATS:
+ gtk_drop_target_async_set_formats (self, g_value_get_boxed (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+gtk_drop_target_async_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GtkDropTargetAsync *self = GTK_DROP_TARGET_ASYNC (object);
+
+ switch (prop_id)
+ {
+ case PROP_ACTIONS:
+ g_value_set_flags (value, gtk_drop_target_async_get_actions (self));
+ break;
+
+ case PROP_FORMATS:
+ g_value_set_boxed (value, gtk_drop_target_async_get_formats (self));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+gtk_drop_target_async_class_init (GtkDropTargetAsyncClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+ GtkEventControllerClass *controller_class = GTK_EVENT_CONTROLLER_CLASS (class);
+
+ object_class->finalize = gtk_drop_target_async_finalize;
+ object_class->set_property = gtk_drop_target_async_set_property;
+ object_class->get_property = gtk_drop_target_async_get_property;
+
+ controller_class->handle_event = gtk_drop_target_async_handle_event;
+ controller_class->filter_event = gtk_drop_target_async_filter_event;
+ controller_class->handle_crossing = gtk_drop_target_async_handle_crossing;
+
+ class->accept = gtk_drop_target_async_accept;
+ class->drag_enter = gtk_drop_target_async_drag_enter;
+ class->drag_motion = gtk_drop_target_async_drag_motion;
+ class->drop = gtk_drop_target_async_drop;
+
+ /**
+ * GtkDropTargetAsync:actions:
+ *
+ * The #GdkDragActions that this drop target supports
+ */
+ properties[PROP_ACTIONS] =
+ g_param_spec_flags ("actions", P_("Actions"), P_("Actions"),
+ GDK_TYPE_DRAG_ACTION, 0,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
+
+ /**
+ * GtkDropTargetAsync:formats:
+ *
+ * The #GdkContentFormats that determines the supported data formats
+ */
+ properties[PROP_FORMATS] =
+ g_param_spec_boxed ("formats", P_("Formats"), P_("Formats"),
+ GDK_TYPE_CONTENT_FORMATS,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
+
+ g_object_class_install_properties (object_class, NUM_PROPERTIES, properties);
+
+ /**
+ * GtkWidget::accept:
+ * @self: the #GtkDropTargetAsync
+ * @drop: the #GdkDrop
+ *
+ * The ::accept signal is emitted on the drop site when a drop operation
+ * is about to begin.
+ * If the drop is not accepted, %FALSE will be returned and the drop target
+ * will ignore the drop. If %TRUE is returned, the drop is accepted for now
+ * but may be rejected later via a call to gtk_drop_target_reject() or
+ * ultimately by returning %FALSE from GtkDropTarget::drop
+ *
+ * The default handler for this signal decides whether to accept the drop
+ * based on the formats provided by the @drop.
+ *
+ * If the decision whether the drop will be accepted or rejected needs
+ * further procesing, such as inspecting the data, this function should
+ * return %TRUE and proceed as is @drop was accepted and if it decides to
+ * reject the drop later, it should call gtk_drop_target_reject_drop().
+ *
+ * Returns: %TRUE if @drop is accepted
+ */
+ signals[ACCEPT] =
+ g_signal_new (I_("accept"),
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GtkDropTargetAsyncClass, accept),
+ g_signal_accumulator_first_wins, NULL,
+ NULL,
+ G_TYPE_BOOLEAN, 1,
+ GDK_TYPE_DROP);
+
+ /**
+ * GtkDropTargetAsync::drag-enter:
+ * @self: the #GtkDropTargetAsync
+ * @drop: the #GdkDrop
+ * @x: the x coordinate of the current pointer position
+ * @y: the y coordinate of the current pointer position
+ *
+ * The ::drag-enter signal is emitted on the drop site when the pointer
+ * enters the widget. It can be used to set up custom highlighting.
+ *
+ * Returns: Preferred action for this drag operation.
+ */
+ signals[DRAG_ENTER] =
+ g_signal_new (I_("drag-enter"),
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GtkDropTargetAsyncClass, drag_enter),
+ g_signal_accumulator_first_wins, NULL,
+ NULL,
+ GDK_TYPE_DRAG_ACTION, 3,
+ GDK_TYPE_DROP, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
+
+ /**
+ * GtkDropTargetAsync::drag-motion:
+ * @self: the #GtkDropTargetAsync
+ * @drop: the #GdkDrop
+ * @x: the x coordinate of the current pointer position
+ * @y: the y coordinate of the current pointer position
+ *
+ * The ::drag-motion signal is emitted while the pointer is moving
+ * over the drop target.
+ *
+ * Returns: Preferred action for this drag operation.
+ */
+ signals[DRAG_MOTION] =
+ g_signal_new (I_("drag-motion"),
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GtkDropTargetAsyncClass, drag_motion),
+ g_signal_accumulator_first_wins, NULL,
+ NULL,
+ GDK_TYPE_DRAG_ACTION, 3,
+ GDK_TYPE_DROP, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
+
+ /**
+ * GtkDropTargetAsync::drag-leave:
+ * @self: the #GtkDropTargetAsync
+ * @drop: the #GdkDrop
+ *
+ * The ::drag-leave signal is emitted on the drop site when the pointer
+ * leaves the widget. Its main purpose it to undo things done in
+ * #GtkDropTargetAsync::drag-enter.
+ */
+ signals[DRAG_LEAVE] =
+ g_signal_new (I_("drag-leave"),
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GtkDropTargetAsyncClass, drag_leave),
+ NULL, NULL,
+ NULL,
+ G_TYPE_NONE, 1,
+ GDK_TYPE_DROP);
+
+ /**
+ * GtkDropTargetAsync::drop:
+ * @self: the #GtkDropTargetAsync
+ * @drop: the #GdkDrop
+ * @x: the x coordinate of the current pointer position
+ * @y: the y coordinate of the current pointer position
+ *
+ * The ::drop signal is emitted on the drop site when the user drops
+ * the data onto the widget. The signal handler must determine whether
+ * the pointer position is in a drop zone or not. If it is not in a drop
+ * zone, it returns %FALSE and no further processing is necessary.
+ *
+ * Otherwise, the handler returns %TRUE. In this case, this handler will
+ * accept the drop. The handler must ensure that gdk_drop_finish() is
+ * called to let the source know that the drop is done. The call to
+ * gtk_drag_finish() must only be done when all data has been received.
+ *
+ * To receive the data, use one of the read functions provides by #GdkDrop
+ * such as gdk_drop_read_async() or gdk_drop_read_value_async().
+ *
+ * Returns: whether the drop is accepted at the given pointer position
+ */
+ signals[DROP] =
+ g_signal_new (I_("drop"),
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ g_signal_accumulator_first_wins, NULL,
+ NULL,
+ G_TYPE_BOOLEAN, 3,
+ GDK_TYPE_DROP, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
+}
+
+static void
+gtk_drop_target_async_init (GtkDropTargetAsync *self)
+{
+}
+
+/**
+ * gtk_drop_target_async_new:
+ * @formats: (nullable) (transfer full): the supported data formats
+ * @actions: the supported actions
+ *
+ * Creates a new #GtkDropTargetAsync object.
+ *
+ * Returns: the new #GtkDropTargetAsync
+ */
+GtkDropTargetAsync *
+gtk_drop_target_async_new (GdkContentFormats *formats,
+ GdkDragAction actions)
+{
+ GtkDropTargetAsync *result;
+
+ result = g_object_new (GTK_TYPE_DROP_TARGET_ASYNC,
+ "formats", formats,
+ "actions", actions,
+ NULL);
+
+ g_clear_pointer (&formats, gdk_content_formats_unref);
+
+ return result;
+}
+
+/**
+ * gtk_drop_target_async_set_formats:
+ * @self: a #GtkDropTargetAsync
+ * @formats: (nullable): the supported data formats or %NULL for
+ * any format.
+ *
+ * Sets the data formats that this drop target will accept.
+ */
+void
+gtk_drop_target_async_set_formats (GtkDropTargetAsync *self,
+ GdkContentFormats *formats)
+{
+ g_return_if_fail (GTK_IS_DROP_TARGET_ASYNC (self));
+
+ if (self->formats == formats)
+ return;
+
+ if (self->formats)
+ gdk_content_formats_unref (self->formats);
+
+ self->formats = formats;
+
+ if (self->formats)
+ gdk_content_formats_ref (self->formats);
+
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FORMATS]);
+}
+
+/**
+ * gtk_drop_target_async_get_formats:
+ * @self: a #GtkDropTargetAsync
+ *
+ * Gets the data formats that this drop target accepts.
+ *
+ * If the result is %NULL, all formats are expected to be supported.
+ *
+ * Returns: (nullable): the supported data formats
+ */
+GdkContentFormats *
+gtk_drop_target_async_get_formats (GtkDropTargetAsync *self)
+{
+ g_return_val_if_fail (GTK_IS_DROP_TARGET_ASYNC (self), NULL);
+
+ return self->formats;
+}
+
+/**
+ * gtk_drop_target_async_set_actions:
+ * @self: a #GtkDropTargetAsync
+ * @actions: the supported actions
+ *
+ * Sets the actions that this drop target supports.
+ */
+void
+gtk_drop_target_async_set_actions (GtkDropTargetAsync *self,
+ GdkDragAction actions)
+{
+ g_return_if_fail (GTK_IS_DROP_TARGET_ASYNC (self));
+
+ if (self->actions == actions)
+ return;
+
+ self->actions = actions;
+
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ACTIONS]);
+}
+
+/**
+ * gtk_drop_target_async_get_actions:
+ * @self: a #GtkDropTargetAsync
+ *
+ * Gets the actions that this drop target supports.
+ *
+ * Returns: the actions that this drop target supports
+ */
+GdkDragAction
+gtk_drop_target_async_get_actions (GtkDropTargetAsync *self)
+{
+ g_return_val_if_fail (GTK_IS_DROP_TARGET_ASYNC (self), 0);
+
+ return self->actions;
+}
+
+/**
+ * gtk_drop_target_async_reject_drop:
+ * @self: a #GtkDropTargetAsync
+ * @drop: the #GdkDrop of an ongoing drag operation
+ *
+ * Sets the @drop as not accepted on this drag site.
+ *
+ * This function should be used when delaying the decision
+ * on whether to accept a drag or not until after reading
+ * the data.
+ */
+void
+gtk_drop_target_async_reject_drop (GtkDropTargetAsync *self,
+ GdkDrop *drop)
+{
+ g_return_if_fail (GTK_IS_DROP_TARGET_ASYNC (self));
+ g_return_if_fail (GDK_IS_DROP (drop));
+ g_return_if_fail (self->drop == drop);
+
+ if (self->rejected)
+ return;
+
+ self->rejected = TRUE;
+ gtk_widget_unset_state_flags (gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (self)),
+ GTK_STATE_FLAG_DROP_ACTIVE);
+}
--- /dev/null
+/* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GTK+ Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#ifndef __GTK_DROP_TARGET_ASYNC_H__
+#define __GTK_DROP_TARGET_ASYNC_H__
+
+
+#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gtk/gtk.h> can be included directly."
+#endif
+
+#include <gtk/gtkwidget.h>
+
+
+G_BEGIN_DECLS
+
+typedef struct _GtkDropTargetAsync GtkDropTargetAsync;
+typedef struct _GtkDropTargetAsyncClass GtkDropTargetAsyncClass;
+
+
+#define GTK_TYPE_DROP_TARGET_ASYNC (gtk_drop_target_async_get_type ())
+#define GTK_DROP_TARGET_ASYNC(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_DROP_TARGET_ASYNC, GtkDropTargetAsync))
+#define GTK_DROP_TARGET_ASYNC_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GTK_TYPE_DROP_TARGET_ASYNC, GtkDropTargetAsyncClass))
+#define GTK_IS_DROP_TARGET_ASYNC(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_DROP_TARGET_ASYNC))
+#define GTK_IS_DROP_TARGET_ASYNC_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GTK_TYPE_DROP_TARGET_ASYNC))
+#define GTK_DROP_TARGET_ASYNC_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_DROP_TARGET_ASYNC, GtkDropTargetAsyncClass))
+
+
+GDK_AVAILABLE_IN_ALL
+GType gtk_drop_target_async_get_type (void) G_GNUC_CONST;
+
+GDK_AVAILABLE_IN_ALL
+GtkDropTargetAsync * gtk_drop_target_async_new (GdkContentFormats *formats,
+ GdkDragAction actions);
+
+GDK_AVAILABLE_IN_ALL
+void gtk_drop_target_async_set_formats (GtkDropTargetAsync *self,
+ GdkContentFormats *formats);
+GDK_AVAILABLE_IN_ALL
+GdkContentFormats * gtk_drop_target_async_get_formats (GtkDropTargetAsync *self);
+
+GDK_AVAILABLE_IN_ALL
+void gtk_drop_target_async_set_actions (GtkDropTargetAsync *self,
+ GdkDragAction actions);
+GDK_AVAILABLE_IN_ALL
+GdkDragAction gtk_drop_target_async_get_actions (GtkDropTargetAsync *self);
+
+GDK_AVAILABLE_IN_ALL
+void gtk_drop_target_async_reject_drop (GtkDropTargetAsync *self,
+ GdkDrop *drop);
+
+
+G_END_DECLS
+
+#endif /* __GTK_DROP_TARGET_ASYNC_H__ */
#include "gtkcellrendererpixbuf.h"
#include "gtkcombobox.h"
#include "gtkcssiconthemevalueprivate.h"
-#include "gtkdragdest.h"
+#include "gtkdroptarget.h"
#include "gtkicontheme.h"
#include "gtkimage.h"
#include "gtklabel.h"
/* GtkWidget Functions */
static void gtk_file_chooser_button_destroy (GtkWidget *widget);
-static gboolean gtk_file_chooser_button_drag_drop (GtkDropTarget *dest,
- GdkDrop *drop,
- int x,
- int y,
- GtkWidget *widget);
static void gtk_file_chooser_button_show (GtkWidget *widget);
static void gtk_file_chooser_button_hide (GtkWidget *widget);
static void gtk_file_chooser_button_root (GtkWidget *widget);
G_IMPLEMENT_INTERFACE (GTK_TYPE_FILE_CHOOSER,
gtk_file_chooser_button_file_chooser_iface_init))
+struct DndSelectFolderData
+{
+ GtkFileSystem *file_system;
+ GtkFileChooserButton *button;
+ GtkFileChooserAction action;
+ GFile *file;
+ gchar **uris;
+ guint i;
+ gboolean selected;
+};
+
+static void
+dnd_select_folder_get_info_cb (GCancellable *cancellable,
+ GFileInfo *info,
+ const GError *error,
+ gpointer user_data)
+{
+ struct DndSelectFolderData *data = user_data;
+ GtkFileChooserButton *button = data->button;
+ GtkFileChooserButtonPrivate *priv = gtk_file_chooser_button_get_instance_private (button);
+ gboolean cancelled = g_cancellable_is_cancelled (cancellable);
+
+ if (cancellable != priv->dnd_select_folder_cancellable)
+ {
+ g_object_unref (data->button);
+ g_object_unref (data->file);
+ g_strfreev (data->uris);
+ g_free (data);
+
+ g_object_unref (cancellable);
+ return;
+ }
+
+ priv->dnd_select_folder_cancellable = NULL;
+
+ if (!cancelled && !error && info != NULL)
+ {
+ gboolean is_folder;
+
+ is_folder = _gtk_file_info_consider_as_directory (info);
+
+ data->selected =
+ (((data->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER && is_folder) ||
+ (data->action == GTK_FILE_CHOOSER_ACTION_OPEN && !is_folder)) &&
+ gtk_file_chooser_select_file (GTK_FILE_CHOOSER (data->button), data->file, NULL));
+ }
+ else
+ data->selected = FALSE;
+
+ if (data->selected || data->uris[++data->i] == NULL)
+ {
+ g_signal_emit (data->button, file_chooser_button_signals[FILE_SET], 0);
+
+ g_object_unref (data->button);
+ g_object_unref (data->file);
+ g_strfreev (data->uris);
+ g_free (data);
+
+ g_object_unref (cancellable);
+ return;
+ }
+
+ if (data->file)
+ g_object_unref (data->file);
+
+ data->file = g_file_new_for_uri (data->uris[data->i]);
+
+ priv->dnd_select_folder_cancellable =
+ _gtk_file_system_get_info (data->file_system, data->file,
+ "standard::type",
+ dnd_select_folder_get_info_cb, user_data);
+
+ g_object_unref (cancellable);
+}
+
+static gboolean
+gtk_file_chooser_button_drop (GtkDropTarget *target,
+ const GValue *value,
+ double x,
+ double y,
+ GtkFileChooserButton *button)
+{
+ GtkFileChooserButtonPrivate *priv = gtk_file_chooser_button_get_instance_private (button);
+ struct DndSelectFolderData *info;
+ GFile *file;
+
+ file = g_value_get_object (value);
+
+ info = g_new0 (struct DndSelectFolderData, 1);
+ info->button = g_object_ref (button);
+ info->i = 0;
+ info->uris = g_new0 (char *, 2);
+ info->selected = FALSE;
+ info->file_system = priv->fs;
+ g_object_get (priv->chooser, "action", &info->action, NULL);
+
+ info->file = g_object_ref (file);
+
+ if (priv->dnd_select_folder_cancellable)
+ g_cancellable_cancel (priv->dnd_select_folder_cancellable);
+
+ priv->dnd_select_folder_cancellable =
+ _gtk_file_system_get_info (priv->fs, info->file,
+ "standard::type",
+ dnd_select_folder_get_info_cb, info);
+
+ return TRUE;
+}
+
static void
gtk_file_chooser_button_class_init (GtkFileChooserButtonClass * class)
{
GtkFileChooserButtonPrivate *priv = gtk_file_chooser_button_get_instance_private (button);
GtkWidget *box;
GtkWidget *icon;
- GdkContentFormatsBuilder *builder;
- GtkDropTarget *dest;
+ GtkDropTarget *target;
priv->button = gtk_button_new ();
g_signal_connect (priv->button, "clicked", G_CALLBACK (button_clicked_cb), button);
NULL, NULL);
/* DnD */
- builder = gdk_content_formats_builder_new ();
- gdk_content_formats_builder_add_gtype (builder, G_TYPE_STRING);
- gdk_content_formats_builder_add_gtype (builder, GDK_TYPE_FILE_LIST);
- dest = gtk_drop_target_new (gdk_content_formats_builder_free_to_formats (builder),
- GDK_ACTION_COPY);
- g_signal_connect (dest, "drag-drop", G_CALLBACK (gtk_file_chooser_button_drag_drop), button);
- gtk_widget_add_controller (GTK_WIDGET (button), GTK_EVENT_CONTROLLER (dest));
+ target = gtk_drop_target_new (G_TYPE_FILE, GDK_ACTION_COPY);
+ g_signal_connect (target, "drop", G_CALLBACK (gtk_file_chooser_button_drop), button);
+ gtk_widget_add_controller (GTK_WIDGET (button), GTK_EVENT_CONTROLLER (target));
}
GTK_WIDGET_CLASS (gtk_file_chooser_button_parent_class)->destroy (widget);
}
-struct DndSelectFolderData
-{
- GtkFileSystem *file_system;
- GtkFileChooserButton *button;
- GtkFileChooserAction action;
- GFile *file;
- gchar **uris;
- guint i;
- gboolean selected;
-};
-
-static void
-dnd_select_folder_get_info_cb (GCancellable *cancellable,
- GFileInfo *info,
- const GError *error,
- gpointer user_data)
-{
- struct DndSelectFolderData *data = user_data;
- GtkFileChooserButton *button = data->button;
- GtkFileChooserButtonPrivate *priv = gtk_file_chooser_button_get_instance_private (button);
- gboolean cancelled = g_cancellable_is_cancelled (cancellable);
-
- if (cancellable != priv->dnd_select_folder_cancellable)
- {
- g_object_unref (data->button);
- g_object_unref (data->file);
- g_strfreev (data->uris);
- g_free (data);
-
- g_object_unref (cancellable);
- return;
- }
-
- priv->dnd_select_folder_cancellable = NULL;
-
- if (!cancelled && !error && info != NULL)
- {
- gboolean is_folder;
-
- is_folder = _gtk_file_info_consider_as_directory (info);
-
- data->selected =
- (((data->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER && is_folder) ||
- (data->action == GTK_FILE_CHOOSER_ACTION_OPEN && !is_folder)) &&
- gtk_file_chooser_select_file (GTK_FILE_CHOOSER (data->button), data->file, NULL));
- }
- else
- data->selected = FALSE;
-
- if (data->selected || data->uris[++data->i] == NULL)
- {
- g_signal_emit (data->button, file_chooser_button_signals[FILE_SET], 0);
-
- g_object_unref (data->button);
- g_object_unref (data->file);
- g_strfreev (data->uris);
- g_free (data);
-
- g_object_unref (cancellable);
- return;
- }
-
- if (data->file)
- g_object_unref (data->file);
-
- data->file = g_file_new_for_uri (data->uris[data->i]);
-
- priv->dnd_select_folder_cancellable =
- _gtk_file_system_get_info (data->file_system, data->file,
- "standard::type",
- dnd_select_folder_get_info_cb, user_data);
-
- g_object_unref (cancellable);
-}
-
-static void
-dnd_select_file (GtkFileChooserButton *button,
- GFile *file)
-{
- GtkFileChooserButtonPrivate *priv = gtk_file_chooser_button_get_instance_private (button);
- struct DndSelectFolderData *info;
-
- info = g_new0 (struct DndSelectFolderData, 1);
- info->button = g_object_ref (button);
- info->i = 0;
- info->uris = g_new0 (char *, 2);
- info->selected = FALSE;
- info->file_system = priv->fs;
- g_object_get (priv->chooser, "action", &info->action, NULL);
-
- info->file = g_object_ref (file);
-
- if (priv->dnd_select_folder_cancellable)
- g_cancellable_cancel (priv->dnd_select_folder_cancellable);
-
- priv->dnd_select_folder_cancellable =
- _gtk_file_system_get_info (priv->fs, info->file,
- "standard::type",
- dnd_select_folder_get_info_cb, info);
-}
-
-static void
-got_file (GObject *source,
- GAsyncResult *result,
- gpointer data)
-{
- GtkFileChooserButton *button = GTK_FILE_CHOOSER_BUTTON (data);
- GdkDrop *drop = GDK_DROP (source);
- const GValue *value;
-
- value = gdk_drop_read_value_finish (drop, result, NULL);
- if (value)
- {
- GFile *file;
-
- file = g_value_get_object (value);
- dnd_select_file (button, file);
- }
-}
-
-static void
-got_text (GObject *source,
- GAsyncResult *result,
- gpointer data)
-{
- GtkFileChooserButton *button = GTK_FILE_CHOOSER_BUTTON (data);
- GdkDrop *drop = GDK_DROP (source);
- char *str;
-
- str = gdk_drop_read_text_finish (drop, result, NULL);
- if (str)
- {
- GFile *file;
-
- file = g_file_new_for_uri (str);
- dnd_select_file (button, file);
- g_object_unref (file);
- }
-
-}
-
-static gboolean
-gtk_file_chooser_button_drag_drop (GtkDropTarget *dest,
- GdkDrop *drop,
- int x,
- int y,
- GtkWidget *button)
-{
- if (gdk_drop_has_value (drop, G_TYPE_FILE))
- {
- gdk_drop_read_value_async (drop, G_TYPE_FILE, G_PRIORITY_DEFAULT, NULL, got_file, button);
- return TRUE;
- }
- else
- {
- gdk_drop_read_text_async (drop, NULL, got_text, button);
- return TRUE;
- }
-
- return FALSE;
-
-}
-
static void
gtk_file_chooser_button_show (GtkWidget *widget)
{
#include "gtkcomboboxtext.h"
#include "gtkcssnumbervalueprivate.h"
#include "gtkdragsource.h"
-#include "gtkdragdest.h"
+#include "gtkdroptarget.h"
#include "gtkentry.h"
#include "gtkfilechooserprivate.h"
#include "gtkfilechooserdialog.h"
g_object_unref (cancellable);
}
-static void
-file_list_drag_data_received_cb (GObject *source,
- GAsyncResult *result,
- gpointer user_data)
+static gboolean
+file_list_drag_drop_cb (GtkDropTarget *dest,
+ const GValue *value,
+ double x,
+ double y,
+ GtkFileChooserWidget *impl)
{
- GtkFileChooserWidget *impl = GTK_FILE_CHOOSER_WIDGET (user_data);
GtkFileChooserWidgetPrivate *priv = gtk_file_chooser_widget_get_instance_private (impl);
- GdkDrop *drop = GDK_DROP (source);
GSList *files;
- const GValue *value;
FileListDragData *data;
- value = gdk_drop_read_value_finish (drop, result, NULL);
- if (value == NULL)
- {
- gdk_drop_finish (drop, 0);
- return;
- }
-
files = g_value_get_boxed (value);
data = g_new0 (FileListDragData, 1);
file_list_drag_data_received_get_info_cb,
data);
- gdk_drop_finish (drop, gdk_drop_get_actions (drop));
-}
-
-/* Don't do anything with the drag_drop signal */
-static gboolean
-file_list_drag_drop_cb (GtkDropTarget *dest,
- GdkDrop *drop,
- int x,
- int y,
- GtkFileChooserWidget *impl)
-{
- gdk_drop_read_value_async (drop, GDK_TYPE_FILE_LIST, G_PRIORITY_DEFAULT, NULL, file_list_drag_data_received_cb, impl);
-
- return TRUE;
-}
-
-/* Disable the normal tree drag motion handler, it makes it look like you're
- dropping the dragged item onto a tree item */
-static gboolean
-file_list_drag_accept_cb (GtkDropTarget *dest,
- GdkDrop *drop,
- GtkFileChooserWidget *impl)
-{
- g_signal_stop_emission_by_name (dest, "accept");
return TRUE;
}
GtkCellRenderer *cell;
GList *cells;
GFile *file;
- GtkDropTarget *dest;
+ GtkDropTarget *target;
/* Setup file list treeview */
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->browse_files_tree_view));
gdk_content_formats_new_for_gtype (GDK_TYPE_FILE_LIST),
GDK_ACTION_COPY | GDK_ACTION_MOVE);
- dest = gtk_drop_target_new (gdk_content_formats_new_for_gtype (GDK_TYPE_FILE_LIST),
- GDK_ACTION_COPY | GDK_ACTION_MOVE);
- g_signal_connect (dest, "accept", G_CALLBACK (file_list_drag_accept_cb), impl);
- g_signal_connect (dest, "drag-drop", G_CALLBACK (file_list_drag_drop_cb), impl);
- gtk_widget_add_controller (priv->browse_files_tree_view, GTK_EVENT_CONTROLLER (dest));
+ target = gtk_drop_target_new (GDK_TYPE_FILE_LIST, GDK_ACTION_COPY | GDK_ACTION_MOVE);
+ g_signal_connect (target, "drop", G_CALLBACK (file_list_drag_drop_cb), impl);
+ gtk_widget_add_controller (priv->browse_files_tree_view, GTK_EVENT_CONTROLLER (target));
/* File browser treemodel columns are shared between GtkFileChooser implementations,
* so we don't set cell renderer attributes in GtkBuilder, but rather keep that
#include "gtkcellrenderertext.h"
#include "gtkcombobox.h"
#include "gtkcssnodeprivate.h"
-#include "gtkdragdest.h"
#include "gtkdragsource.h"
#include "gtkentry.h"
#include "gtkintl.h"
#include "gtkwindow.h"
#include "gtkeventcontrollerkey.h"
#include "gtkdragsource.h"
-#include "gtkdragdest.h"
#include "gtkdragicon.h"
#include "gtknative.h"
GtkTreePath *source_row);
/* Target side drag signals */
-static void gtk_icon_view_drag_leave (GtkDropTarget *dest,
- GdkDrop *drop,
- GtkIconView *icon_view);
-static void gtk_icon_view_drag_motion (GtkDropTarget *dest,
- GdkDrop *drop,
- int x,
- int y,
- GtkIconView *icon_view);
-static gboolean gtk_icon_view_drag_drop (GtkDropTarget *dest,
- GdkDrop *drop,
- int x,
- int y,
- GtkIconView *icon_view);
+static void gtk_icon_view_drag_leave (GtkDropTargetAsync *dest,
+ GdkDrop *drop,
+ GtkIconView *icon_view);
+static GdkDragAction gtk_icon_view_drag_motion (GtkDropTargetAsync *dest,
+ GdkDrop *drop,
+ double x,
+ double y,
+ GtkIconView *icon_view);
+static gboolean gtk_icon_view_drag_drop (GtkDropTargetAsync *dest,
+ GdkDrop *drop,
+ double x,
+ double y,
+ GtkIconView *icon_view);
static void gtk_icon_view_drag_data_received (GObject *source,
GAsyncResult *result,
gpointer data);
}
static gboolean
-set_destination (GtkIconView *icon_view,
- GtkDropTarget *dest,
- gint x,
- gint y,
- GdkDragAction *suggested_action,
- GType *target)
+set_destination (GtkIconView *icon_view,
+ GtkDropTargetAsync *dest,
+ gint x,
+ gint y,
+ GdkDragAction *suggested_action,
+ GType *target)
{
GtkWidget *widget;
GtkTreePath *path = NULL;
return FALSE; /* no longer a drop site */
}
- formats = gtk_drop_target_get_formats (dest);
+ formats = gtk_drop_target_async_get_formats (dest);
*target = gdk_content_formats_match_gtype (formats, formats);
if (*target == G_TYPE_INVALID)
return FALSE;
/* Target side drag signals */
static void
-gtk_icon_view_drag_leave (GtkDropTarget *dest,
- GdkDrop *drop,
- GtkIconView *icon_view)
+gtk_icon_view_drag_leave (GtkDropTargetAsync *dest,
+ GdkDrop *drop,
+ GtkIconView *icon_view)
{
/* unset any highlight row */
gtk_icon_view_set_drag_dest_item (icon_view,
remove_scroll_timeout (icon_view);
}
-static void
-gtk_icon_view_drag_motion (GtkDropTarget *dest,
- GdkDrop *drop,
- int x,
- int y,
- GtkIconView *icon_view)
+static GdkDragAction
+gtk_icon_view_drag_motion (GtkDropTargetAsync *dest,
+ GdkDrop *drop,
+ double x,
+ double y,
+ GtkIconView *icon_view)
{
GtkTreePath *path = NULL;
GtkIconViewDropPosition pos;
GdkDragAction suggested_action = 0;
GType target;
gboolean empty;
+ GdkDragAction result;
if (!set_destination (icon_view, dest, x, y, &suggested_action, &target))
- {
- gdk_drop_status (drop, 0);
- return;
- }
+ return 0;
gtk_icon_view_get_drag_dest_item (icon_view, &path, &pos);
if (path == NULL && !empty)
{
/* Can't drop here. */
- gdk_drop_status (drop, 0);
+ result = 0;
}
else
{
else
{
set_status_pending (drop, 0);
- gdk_drop_status (drop, suggested_action);
}
+ result = suggested_action;
}
if (path)
gtk_tree_path_free (path);
+
+ return result;
}
static gboolean
-gtk_icon_view_drag_drop (GtkDropTarget *dest,
- GdkDrop *drop,
- int x,
- int y,
- GtkIconView *icon_view)
+gtk_icon_view_drag_drop (GtkDropTargetAsync *dest,
+ GdkDrop *drop,
+ double x,
+ double y,
+ GtkIconView *icon_view)
{
GtkTreePath *path;
GdkDragAction suggested_action = 0;
if (!icon_view->priv->dest_set)
return FALSE;
- if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag-drop"))
+ if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drop"))
return FALSE;
if (!set_destination (icon_view, dest, x, y, &suggested_action, &target))
suggested_action = 0;
}
- gdk_drop_status (drop, suggested_action);
-
if (path)
gtk_tree_path_free (path);
g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
- icon_view->priv->dest = gtk_drop_target_new (gdk_content_formats_ref (formats), actions);
+ icon_view->priv->dest = gtk_drop_target_async_new (gdk_content_formats_ref (formats), actions);
g_signal_connect (icon_view->priv->dest, "drag-leave", G_CALLBACK (gtk_icon_view_drag_leave), icon_view);
+ g_signal_connect (icon_view->priv->dest, "drag-enter", G_CALLBACK (gtk_icon_view_drag_motion), icon_view);
g_signal_connect (icon_view->priv->dest, "drag-motion", G_CALLBACK (gtk_icon_view_drag_motion), icon_view);
- g_signal_connect (icon_view->priv->dest, "drag-drop", G_CALLBACK (gtk_icon_view_drag_drop), icon_view);
+ g_signal_connect (icon_view->priv->dest, "drop", G_CALLBACK (gtk_icon_view_drag_drop), icon_view);
gtk_widget_add_controller (GTK_WIDGET (icon_view), GTK_EVENT_CONTROLLER (icon_view->priv->dest));
icon_view->priv->dest_actions = actions;
#include "gtk/gtkiconview.h"
#include "gtk/gtkcssnodeprivate.h"
-#include "gtk/gtkdragdest.h"
-#include "gtk/gtkgestureclick.h"
#include "gtk/gtkeventcontrollermotion.h"
#include "gtk/gtkdragsource.h"
+#include "gtk/gtkdroptargetasync.h"
+#include "gtk/gtkgestureclick.h"
#ifndef __GTK_ICON_VIEW_PRIVATE_H__
#define __GTK_ICON_VIEW_PRIVATE_H__
gint press_start_y;
GdkContentFormats *source_formats;
- GtkDropTarget *dest;
+ GtkDropTargetAsync *dest;
GtkCssNode *dndnode;
GdkDrag *drag;
#include "gtkbuildable.h"
#include "gtkcontainerprivate.h"
#include "gtkcssnodeprivate.h"
-#include "gtkdragdest.h"
#include "gtkgestureclick.h"
#include "gtkintl.h"
#include "gtkmain.h"
#include "gtkaccelmapprivate.h"
#include "gtkbox.h"
#include "gtkdebug.h"
-#include "gtkdragdestprivate.h"
+#include "gtkdropprivate.h"
#include "gtkmain.h"
#include "gtkmediafileprivate.h"
#include "gtkmodulesprivate.h"
event, gdk_crossing_event_get_mode (event), NULL);
break;
case GDK_DRAG_LEAVE:
- old_target = update_pointer_focus_state (toplevel, event, NULL);
- gtk_synthesize_crossing_events (GTK_ROOT (toplevel), GTK_CROSSING_DROP, old_target, NULL,
- event, GDK_CROSSING_NORMAL, gdk_drag_event_get_drop (event));
+ {
+ GdkDrop *drop = gdk_drag_event_get_drop (event);
+ old_target = update_pointer_focus_state (toplevel, event, NULL);
+ gtk_drop_begin_event (drop, GDK_DRAG_LEAVE);
+ gtk_synthesize_crossing_events (GTK_ROOT (toplevel), GTK_CROSSING_DROP, old_target, NULL,
+ event, GDK_CROSSING_NORMAL, drop);
+ gtk_drop_end_event (drop);
+ }
break;
case GDK_ENTER_NOTIFY:
if (gdk_crossing_event_get_mode (event) == GDK_CROSSING_GRAB ||
gtk_window_maybe_update_cursor (toplevel, NULL, device);
}
- else if (type == GDK_DRAG_ENTER || type == GDK_DRAG_MOTION || type == GDK_DROP_START)
+ else if ((old_target != target) &&
+ (type == GDK_DRAG_ENTER || type == GDK_DRAG_MOTION || type == GDK_DROP_START))
{
+ GdkDrop *drop = gdk_drag_event_get_drop (event);
+ gtk_drop_begin_event (drop, type);
gtk_synthesize_crossing_events (GTK_ROOT (toplevel), GTK_CROSSING_DROP, old_target, target,
event, GDK_CROSSING_NORMAL, gdk_drag_event_get_drop (event));
+ gtk_drop_end_event (drop);
}
else if (type == GDK_TOUCH_BEGIN)
gtk_window_set_pointer_focus_grab (toplevel, device, sequence, target);
case GDK_ENTER_NOTIFY:
case GDK_LEAVE_NOTIFY:
+ case GDK_DRAG_ENTER:
+ case GDK_DRAG_LEAVE:
/* Crossing event propagation happens during picking */
break;
case GDK_DRAG_MOTION:
case GDK_DROP_START:
- if (gtk_propagate_event (target_widget, event))
- break;
- G_GNUC_FALLTHROUGH;
-
- case GDK_DRAG_ENTER:
- case GDK_DRAG_LEAVE:
- /* Crossing event propagation happens during picking */
- gtk_drag_dest_handle_event (target_widget, event);
+ {
+ GdkDrop *drop = gdk_drag_event_get_drop (event);
+ gtk_drop_begin_event (drop, gdk_event_get_event_type (event));
+ gtk_propagate_event (target_widget, event);
+ gtk_drop_end_event (drop);
+ }
break;
case GDK_EVENT_LAST:
#include "gtkbuildable.h"
#include "gtkbutton.h"
#include "gtkcssstylepropertyprivate.h"
-#include "gtkdragdest.h"
+#include "gtkdroptarget.h"
#include "gtkdragicon.h"
#include "gtkdropcontrollermotion.h"
#include "gtkeventcontrollermotion.h"
static void gtk_notebook_drag_cancel_cb (GdkDrag *drag,
GdkDragCancelReason reason,
GtkWidget *widget);
-static void gtk_notebook_drag_motion (GtkDropTarget *dest,
- GdkDrop *drop,
- int x,
- int y);
+static GdkDragAction gtk_notebook_drag_motion(GtkDropTarget *dest,
+ double x,
+ double y,
+ GtkNotebook *notebook);
static gboolean gtk_notebook_drag_drop (GtkDropTarget *dest,
- GdkDrop *drop,
- int x,
- int y);
+ const GValue *value,
+ double x,
+ double y,
+ GtkNotebook *notebook);
/*** GtkContainer Methods ***/
static void gtk_notebook_add (GtkContainer *container,
gtk_widget_set_vexpand (priv->stack_widget, TRUE);
gtk_widget_set_parent (priv->stack_widget, GTK_WIDGET (notebook));
- dest = gtk_drop_target_new (gdk_content_formats_new_for_gtype (GTK_TYPE_NOTEBOOK_PAGE), GDK_ACTION_MOVE);
- g_signal_connect (dest, "drag-motion", G_CALLBACK (gtk_notebook_drag_motion), NULL);
- g_signal_connect (dest, "drag-drop", G_CALLBACK (gtk_notebook_drag_drop), NULL);
+ dest = gtk_drop_target_new (GTK_TYPE_NOTEBOOK_PAGE, GDK_ACTION_MOVE);
+ gtk_drop_target_set_preload (dest, TRUE);
+ g_signal_connect (dest, "motion", G_CALLBACK (gtk_notebook_drag_motion), notebook);
+ g_signal_connect (dest, "drop", G_CALLBACK (gtk_notebook_drag_drop), notebook);
gtk_widget_add_controller (GTK_WIDGET (priv->tabs_widget), GTK_EVENT_CONTROLLER (dest));
gesture = gtk_gesture_click_new ();
return FALSE;
}
-static void
-gtk_notebook_drag_motion (GtkDropTarget *dest,
- GdkDrop *drop,
- int x,
- int y)
+static gboolean
+gtk_notebook_can_drag_from (GtkNotebook *self,
+ GtkNotebook *other,
+ GtkNotebookPage *page)
{
- GtkWidget *tabs = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (dest));
- GtkWidget *widget = gtk_widget_get_ancestor (tabs, GTK_TYPE_NOTEBOOK);
- GtkNotebook *notebook = GTK_NOTEBOOK (widget);
- GtkNotebookPrivate *priv = notebook->priv;
- GdkContentFormats *formats;
-
- priv->mouse_x = x;
- priv->mouse_y = y;
-
- formats = gtk_drop_target_get_formats (dest);
- if (gdk_content_formats_contain_gtype (formats, GTK_TYPE_NOTEBOOK_PAGE))
- {
- GQuark group, source_group;
- GtkWidget *source_child;
- GdkDrag *drag = gdk_drop_get_drag (drop);
-
- if (!drag)
- {
- gdk_drop_status (drop, 0);
- }
- else
- {
- GtkNotebook *source = GTK_NOTEBOOK (g_object_get_data (G_OBJECT (drag), "gtk-notebook-drag-origin"));
+ /* always allow dragging inside self */
+ if (self == other)
+ return TRUE;
- g_assert (source->priv->cur_page != NULL);
- source_child = source->priv->cur_page->child;
+ /* if the groups don't match, fail */
+ if (self->priv->group == 0 ||
+ self->priv->group != other->priv->group)
+ return FALSE;
- group = notebook->priv->group;
- source_group = source->priv->group;
+ /* Check that the dragged page is not a parent of the notebook
+ * being dragged into */
+ if (GTK_WIDGET (self) == page->child ||
+ gtk_widget_is_ancestor (GTK_WIDGET (self), GTK_WIDGET (page->child)) ||
+ GTK_WIDGET (self) == page->tab_label ||
+ gtk_widget_is_ancestor (GTK_WIDGET (self), GTK_WIDGET (page->tab_label)))
+ return FALSE;
- if (group != 0 && group == source_group &&
- !(widget == source_child ||
- gtk_widget_is_ancestor (widget, source_child)))
- {
- gdk_drop_status (drop, GDK_ACTION_MOVE);
- }
- else
- {
- /* it's a tab, but doesn't share
- * ID with this notebook */
- gdk_drop_status (drop, 0);
- }
- }
- }
+ return TRUE;
}
-static void
-got_page (GObject *source,
- GAsyncResult *result,
- gpointer data)
+static GdkDragAction
+gtk_notebook_drag_motion (GtkDropTarget *dest,
+ double x,
+ double y,
+ GtkNotebook *notebook)
{
- GtkNotebook *notebook = GTK_NOTEBOOK (data);
- GdkDrop *drop = GDK_DROP (source);
- GdkDrag *drag = gdk_drop_get_drag (drop);
- GtkWidget *source_widget;
- const GValue *value;
+ GtkNotebookPrivate *priv = notebook->priv;
+ GdkDrag *drag = gdk_drop_get_drag (gtk_drop_target_get_drop (dest));
+ GtkNotebook *source;
- source_widget = GTK_WIDGET (drag ? g_object_get_data (G_OBJECT (drag), "gtk-notebook-drag-origin") : NULL);
+ priv->mouse_x = x;
+ priv->mouse_y = y;
- value = gdk_drop_read_value_finish (drop, result, NULL);
+ if (!drag)
+ return 0;
- if (value)
- {
- GtkNotebookPage *page = g_value_get_object (value);
+ source = GTK_NOTEBOOK (g_object_get_data (G_OBJECT (drag), "gtk-notebook-drag-origin"));
+ g_assert (source->priv->cur_page != NULL);
- do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, page->child);
- gdk_drop_finish (drop, GDK_ACTION_MOVE);
- }
- else
- gdk_drop_finish (drop, 0);
+ if (!gtk_notebook_can_drag_from (notebook, source, source->priv->cur_page))
+ return 0;
+
+ return GDK_ACTION_MOVE;
}
static gboolean
gtk_notebook_drag_drop (GtkDropTarget *dest,
- GdkDrop *drop,
- int x,
- int y)
+ const GValue *value,
+ double x,
+ double y,
+ GtkNotebook *self)
{
- GtkWidget *tabs = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (dest));
- GtkWidget *widget = gtk_widget_get_ancestor (tabs, GTK_TYPE_NOTEBOOK);
- GtkNotebook *notebook = GTK_NOTEBOOK (widget);
- GdkDrag *drag = gdk_drop_get_drag (drop);
- GtkWidget *source_widget;
+ GdkDrag *drag = gdk_drop_get_drag (gtk_drop_target_get_drop (dest));
+ GtkNotebook *source;
+ GtkNotebookPage *page = g_value_get_object (value);
- source_widget = GTK_WIDGET (drag ? g_object_get_data (G_OBJECT (drag), "gtk-notebook-drag-origin") : NULL);
-
- if (GTK_IS_NOTEBOOK (source_widget) &&
- (gdk_drop_get_actions (drop) & GDK_ACTION_MOVE))
- {
- notebook->priv->mouse_x = x;
- notebook->priv->mouse_y = y;
+ source = drag ? g_object_get_data (G_OBJECT (drag), "gtk-notebook-drag-origin") : NULL;
- gdk_drop_read_value_async (drop, GTK_TYPE_NOTEBOOK_PAGE, G_PRIORITY_DEFAULT, NULL, got_page, notebook);
+ if (!gtk_notebook_can_drag_from (self, source, source->priv->cur_page))
+ return FALSE;
- return TRUE;
- }
+ self->priv->mouse_x = x;
+ self->priv->mouse_y = y;
- gdk_drop_finish (drop, 0);
+ do_detach_tab (source, self, page->child);
- return FALSE;
+ return TRUE;
}
/**
#include "gtklabel.h"
#include "gtkbutton.h"
#include "gtklistbox.h"
-#include "gtkdragdest.h"
+#include "gtkdroptarget.h"
#include "gtkseparator.h"
#include "gtkentry.h"
#include "gtkgesturelongpress.h"
GtkWidget *trash_row;
/* DND */
- GSList *drag_list; /* list of GFile */
- gint drag_data_info;
gboolean dragging_over;
GtkWidget *drag_row;
gint drag_row_height;
GtkPlacesOpenFlags open_flags;
guint mounting : 1;
- guint drag_data_received : 1;
- guint drop_occurred : 1;
guint show_recent_set : 1;
guint show_recent : 1;
guint show_desktop_set : 1;
static GMountOperation * get_unmount_operation (GtkPlacesSidebar *sidebar);
-/* Identifiers for target types */
-enum {
- DND_UNKNOWN,
- DND_GTK_SIDEBAR_ROW,
- DND_TEXT_URI_LIST
-};
-
G_DEFINE_TYPE (GtkPlacesSidebar, gtk_places_sidebar, GTK_TYPE_WIDGET);
static void
return ret_action;
}
-static GdkDragAction
-emit_drag_action_ask (GtkPlacesSidebar *sidebar,
- GdkDragAction actions)
-{
- GdkDragAction ret_action = 0;
-
- g_signal_emit (sidebar, places_sidebar_signals[DRAG_ACTION_ASK], 0,
- actions, &ret_action);
-
- return ret_action;
-}
-
static void
emit_drag_perform_drop (GtkPlacesSidebar *sidebar,
GFile *dest_file,
static gboolean
check_valid_drop_target (GtkPlacesSidebar *sidebar,
- GtkSidebarRow *row)
+ GtkSidebarRow *row,
+ const GValue *value)
{
GtkPlacesSidebarPlaceType place_type;
GtkPlacesSidebarSectionType section_type;
GFile *dest_file;
gint drag_action;
+ g_return_val_if_fail (value != NULL, TRUE);
+
if (row == NULL)
return FALSE;
}
/* Dragging a bookmark? */
- if (sidebar->drag_data_received &&
- sidebar->drag_data_info == DND_GTK_SIDEBAR_ROW)
+ if (G_VALUE_HOLDS (value, GTK_TYPE_SIDEBAR_ROW))
{
/* Don't allow reordering bookmarks into non-bookmark areas */
valid = section_type == SECTION_BOOKMARKS;
}
- else
+ else if (G_VALUE_HOLDS (value, GDK_TYPE_FILE_LIST))
{
/* Dragging a file */
if (uri != NULL)
{
dest_file = g_file_new_for_uri (uri);
- drag_action = emit_drag_action_requested (sidebar, dest_file, sidebar->drag_list);
+ drag_action = emit_drag_action_requested (sidebar, dest_file, g_value_get_boxed (value));
valid = drag_action > 0;
g_object_unref (dest_file);
valid = FALSE;
}
}
+ else
+ {
+ g_assert_not_reached ();
+ valid = TRUE;
+ }
g_free (uri);
return valid;
static void
update_possible_drop_targets (GtkPlacesSidebar *sidebar,
- gboolean dragging)
+ const GValue *value)
{
GList *rows;
GList *l;
for (l = rows; l != NULL; l = l->next)
{
- sensitive = !dragging || check_valid_drop_target (sidebar, GTK_SIDEBAR_ROW (l->data));
+ sensitive = value == NULL || check_valid_drop_target (sidebar, GTK_SIDEBAR_ROW (l->data), value);
gtk_widget_set_sensitive (GTK_WIDGET (l->data), sensitive);
}
g_list_free (rows);
}
-static void drag_data_received_callback (GObject *source,
- GAsyncResult *result,
- gpointer user_data);
-
-static gboolean
-get_drag_data (GtkPlacesSidebar *self,
- GtkDropTarget *dest,
- GdkDrop *drop,
- GtkListBoxRow *row)
-{
- GdkContentFormats *formats = gdk_drop_get_formats (drop);
-
- if (row)
- g_object_set_data_full (G_OBJECT (drop), "places-sidebar-row", g_object_ref (row), g_object_unref);
-
- gdk_drop_read_value_async (drop,
- gdk_content_formats_match_gtype (formats, formats),
- G_PRIORITY_DEFAULT,
- NULL,
- drag_data_received_callback,
- self->list_box);
-
- return TRUE;
-}
-
static void
-free_drag_data (GtkPlacesSidebar *sidebar)
+start_drop_feedback (GtkPlacesSidebar *sidebar,
+ const GValue *value)
{
- sidebar->drag_data_received = FALSE;
-
- if (sidebar->drag_list)
- {
- g_slist_free_full (sidebar->drag_list, g_object_unref);
- sidebar->drag_list = NULL;
- }
-}
-
-static void
-start_drop_feedback (GtkPlacesSidebar *sidebar)
-{
- if (sidebar->drag_data_received &&
- sidebar->drag_data_info != DND_GTK_SIDEBAR_ROW)
+ if (value && !G_VALUE_HOLDS (value, GTK_TYPE_SIDEBAR_ROW))
{
gtk_sidebar_row_reveal (GTK_SIDEBAR_ROW (sidebar->new_bookmark_row));
/* If the state is permanent, don't change it. The application controls it. */
sidebar->drop_state = DROP_STATE_NEW_BOOKMARK_ARMED;
}
- update_possible_drop_targets (sidebar, TRUE);
+ update_possible_drop_targets (sidebar, value);
}
static void
stop_drop_feedback (GtkPlacesSidebar *sidebar)
{
- update_possible_drop_targets (sidebar, FALSE);
-
- free_drag_data (sidebar);
+ update_possible_drop_targets (sidebar, NULL);
if (sidebar->drop_state != DROP_STATE_NEW_BOOKMARK_ARMED_PERMANENT &&
sidebar->new_bookmark_row != NULL)
}
sidebar->dragging_over = FALSE;
- sidebar->drag_data_info = DND_UNKNOWN;
}
static GtkWidget *
return g_object_new (GTK_TYPE_SIDEBAR_ROW, "placeholder", TRUE, NULL);
}
-static void
-drag_motion_callback (GtkDropTarget *dest,
- GdkDrop *drop,
- gint x,
- gint y,
- gpointer user_data)
+static GdkDragAction
+drag_motion_callback (GtkDropTarget *target,
+ double x,
+ double y,
+ GtkPlacesSidebar *sidebar)
{
- GtkPlacesSidebar *sidebar = GTK_PLACES_SIDEBAR (user_data);
- gint action;
+ GdkDragAction action;
GtkListBoxRow *row;
GtkPlacesSidebarPlaceType place_type;
gchar *drop_target_uri = NULL;
gint row_index;
gint row_placeholder_index;
+ const GValue *value;
sidebar->dragging_over = TRUE;
action = 0;
gtk_list_box_drag_unhighlight_row (GTK_LIST_BOX (sidebar->list_box));
- /* Nothing to do if no drag data */
- if (!sidebar->drag_data_received &&
- !get_drag_data (sidebar, dest, drop, row))
+ /* Nothing to do if no value yet */
+ value = gtk_drop_target_get_value (target);
+ if (value == NULL)
goto out;
/* Nothing to do if the target is not valid drop destination */
- if (!check_valid_drop_target (sidebar, GTK_SIDEBAR_ROW (row)))
+ if (!check_valid_drop_target (sidebar, GTK_SIDEBAR_ROW (row), value))
goto out;
- if (sidebar->drag_data_received &&
- sidebar->drag_data_info == DND_GTK_SIDEBAR_ROW)
+ if (G_VALUE_HOLDS (value, GTK_TYPE_SIDEBAR_ROW))
{
/* Dragging bookmarks always moves them to another position in the bookmarks list */
action = GDK_ACTION_MOVE;
gtk_list_box_prepend (GTK_LIST_BOX (sidebar->list_box),
sidebar->row_placeholder);
}
- else
+ else if (G_VALUE_HOLDS (value, GDK_TYPE_FILE_LIST))
{
gtk_list_box_drag_highlight_row (GTK_LIST_BOX (sidebar->list_box), row);
* file move/copy operation itself, or if we should only try to
* create bookmarks out of the dragged URIs.
*/
- if (sidebar->drag_list != NULL)
+ if (place_type == PLACES_DROP_FEEDBACK)
{
- if (place_type == PLACES_DROP_FEEDBACK)
- {
- action = GDK_ACTION_COPY;
- }
- else
+ action = GDK_ACTION_COPY;
+ }
+ else
+ {
+ /* uri may be NULL for unmounted volumes, for example, so we don't allow drops there */
+ if (drop_target_uri != NULL)
{
- /* uri may be NULL for unmounted volumes, for example, so we don't allow drops there */
- if (drop_target_uri != NULL)
- {
- GFile *dest_file = g_file_new_for_uri (drop_target_uri);
+ GFile *dest_file = g_file_new_for_uri (drop_target_uri);
- action = emit_drag_action_requested (sidebar, dest_file, sidebar->drag_list);
+ action = emit_drag_action_requested (sidebar, dest_file, g_value_get_boxed (value));
- g_object_unref (dest_file);
- }
+ g_object_unref (dest_file);
}
}
g_free (drop_target_uri);
}
+ else
+ {
+ g_assert_not_reached ();
+ }
out:
- start_drop_feedback (sidebar);
- gdk_drop_status (drop, action);
+ start_drop_feedback (sidebar, value);
+ return action;
}
/* Reorders the bookmark to the specified position */
}
}
-static void
-drag_data_received_callback (GObject *source,
- GAsyncResult *result,
- gpointer user_data)
+static gboolean
+drag_drop_callback (GtkDropTarget *target,
+ const GValue *value,
+ double x,
+ double y,
+ GtkPlacesSidebar *sidebar)
{
- GdkDrop *drop = GDK_DROP (source);
- GtkWidget *list_box = user_data;
- GtkPlacesSidebar *sidebar = GTK_PLACES_SIDEBAR (gtk_widget_get_ancestor (list_box, GTK_TYPE_PLACES_SIDEBAR));
gint target_order_index;
GtkPlacesSidebarPlaceType target_place_type;
GtkPlacesSidebarSectionType target_section_type;
gchar *target_uri;
GtkListBoxRow *target_row;
- GdkDragAction real_action;
- const GValue *value;
-
- value = gdk_drop_read_value_finish (drop, result, NULL);
-
- if (!sidebar->drag_data_received)
- {
- if (G_VALUE_HOLDS (value, GDK_TYPE_FILE_LIST))
- {
- /* Free spurious drag data from previous drags if present */
- if (sidebar->drag_list != NULL)
- g_slist_free_full (sidebar->drag_list, g_object_unref);
- sidebar->drag_list = g_slist_copy_deep (g_value_get_boxed (value), (GCopyFunc) g_object_ref, NULL);
- sidebar->drag_data_info = DND_TEXT_URI_LIST;
- }
- else if (G_VALUE_HOLDS (value, GTK_TYPE_SIDEBAR_ROW))
- {
- sidebar->drag_list = NULL;
- sidebar->drag_data_info = DND_GTK_SIDEBAR_ROW;
- }
- sidebar->drag_data_received = TRUE;
- }
+ gboolean result;
- if (!sidebar->drop_occurred)
- return;
-
- target_row = g_object_get_data (G_OBJECT (drop), "places-sidebar-row");
+ target_row = gtk_list_box_get_row_at_y (GTK_LIST_BOX (sidebar->list_box), y);
if (target_row == NULL)
- return;
+ return FALSE;
- if (!check_valid_drop_target (sidebar, GTK_SIDEBAR_ROW (target_row)))
- return;
+ if (!check_valid_drop_target (sidebar, GTK_SIDEBAR_ROW (target_row), value))
+ return FALSE;
g_object_get (target_row,
"place-type", &target_place_type,
"order-index", &target_order_index,
"uri", &target_uri,
NULL);
- real_action = 0;
+ result = FALSE;
- if (sidebar->drag_data_info == DND_GTK_SIDEBAR_ROW)
+ if (G_VALUE_HOLDS (value, GTK_TYPE_SIDEBAR_ROW))
{
GtkWidget **source_row;
/* A bookmark got reordered */
g_object_get (sidebar->row_placeholder, "order-index", &target_order_index, NULL);
reorder_bookmarks (sidebar, GTK_SIDEBAR_ROW (*source_row), target_order_index);
- real_action = GDK_ACTION_MOVE;
+ result = TRUE;
}
- else
+ else if (G_VALUE_HOLDS (value, GDK_TYPE_FILE_LIST))
{
/* Dropping URIs! */
-
- /* file transfer requested */
- real_action = gdk_drop_get_actions (drop);
-
- if (!gdk_drag_action_is_unique (real_action))
- real_action = emit_drag_action_ask (sidebar, real_action);
-
- if (real_action > 0)
+ if (target_place_type == PLACES_DROP_FEEDBACK)
{
- if (target_place_type == PLACES_DROP_FEEDBACK)
- {
- drop_files_as_bookmarks (sidebar, sidebar->drag_list, target_order_index);
- }
- else
- {
- GFile *dest_file = g_file_new_for_uri (target_uri);
-
- emit_drag_perform_drop (sidebar, dest_file, sidebar->drag_list, real_action);
+ drop_files_as_bookmarks (sidebar, g_value_get_boxed (value), target_order_index);
+ }
+ else
+ {
+ GFile *dest_file = g_file_new_for_uri (target_uri);
+
+ emit_drag_perform_drop (sidebar,
+ dest_file,
+ g_value_get_boxed (value),
+ gdk_drop_get_actions (gtk_drop_target_get_drop (target)));
- g_object_unref (dest_file);
- }
+ g_object_unref (dest_file);
}
+ result = TRUE;
+ }
+ else
+ {
+ g_assert_not_reached ();
}
out:
- sidebar->drop_occurred = FALSE;
- g_object_set_data (G_OBJECT (drop), "places-sidebar-row", NULL);
- gdk_drop_finish (drop, real_action);
stop_drop_feedback (sidebar);
g_free (target_uri);
+ return result;
}
static void
sidebar->drop_state = DROP_STATE_NORMAL;
}
- sidebar->drag_data_received = FALSE;
sidebar->dragging_over = FALSE;
- sidebar->drag_data_info = DND_UNKNOWN;
-}
-
-static gboolean
-drag_drop_callback (GtkDropTarget *dest,
- GdkDrop *drop,
- int x,
- int y,
- gpointer user_data)
-{
- GtkPlacesSidebar *sidebar = GTK_PLACES_SIDEBAR (user_data);
- gboolean retval = FALSE;
- GtkListBoxRow *row;
-
- row = gtk_list_box_get_row_at_y (GTK_LIST_BOX (sidebar->list_box), y);
- sidebar->drop_occurred = TRUE;
-
- retval = get_drag_data (sidebar, dest, drop, row);
-
- return retval;
}
static void
static void
gtk_places_sidebar_init (GtkPlacesSidebar *sidebar)
{
- GtkDropTarget *dest;
+ GtkDropTarget *target;
gboolean show_desktop;
GtkEventController *controller;
GtkGesture *gesture;
- GdkContentFormatsBuilder *builder;
sidebar->cancellable = g_cancellable_new ();
gtk_widget_add_controller (GTK_WIDGET (sidebar), GTK_EVENT_CONTROLLER (gesture));
/* DND support */
- builder = gdk_content_formats_builder_new ();
- gdk_content_formats_builder_add_gtype (builder, GTK_TYPE_SIDEBAR_ROW);
- gdk_content_formats_builder_add_gtype (builder, GDK_TYPE_FILE_LIST);
- dest = gtk_drop_target_new (gdk_content_formats_builder_free_to_formats (builder),
- GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_LINK);
- g_signal_connect (dest, "drag-motion", G_CALLBACK (drag_motion_callback), sidebar);
- g_signal_connect (dest, "drag-drop", G_CALLBACK (drag_drop_callback), sidebar);
- g_signal_connect (dest, "drag-leave", G_CALLBACK (drag_leave_callback), sidebar);
- gtk_widget_add_controller (sidebar->list_box, GTK_EVENT_CONTROLLER (dest));
+ target = gtk_drop_target_new (G_TYPE_INVALID, GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_LINK);
+ gtk_drop_target_set_preload (target, TRUE);
+ gtk_drop_target_set_gtypes (target, (GType[2]) { GTK_TYPE_SIDEBAR_ROW, GDK_TYPE_FILE_LIST }, 2);
+ g_signal_connect (target, "enter", G_CALLBACK (drag_motion_callback), sidebar);
+ g_signal_connect (target, "motion", G_CALLBACK (drag_motion_callback), sidebar);
+ g_signal_connect (target, "drop", G_CALLBACK (drag_drop_callback), sidebar);
+ g_signal_connect (target, "leave", G_CALLBACK (drag_leave_callback), sidebar);
+ gtk_widget_add_controller (sidebar->list_box, GTK_EVENT_CONTROLLER (target));
sidebar->drag_row = NULL;
sidebar->row_placeholder = NULL;
sidebar->dragging_over = FALSE;
- sidebar->drag_data_info = DND_UNKNOWN;
gtk_container_add (GTK_CONTAINER (sidebar->swin), sidebar->list_box);
sidebar->cancellable = NULL;
}
- free_drag_data (sidebar);
-
if (sidebar->bookmarks_manager != NULL)
{
_gtk_bookmarks_manager_free (sidebar->bookmarks_manager);
if (visible)
{
sidebar->drop_state = DROP_STATE_NEW_BOOKMARK_ARMED_PERMANENT;
- start_drop_feedback (sidebar);
+ start_drop_feedback (sidebar, NULL);
}
else
{
#include "gtkbutton.h"
#include "gtkcssnodeprivate.h"
#include "gtkdebug.h"
+#include "gtkdragicon.h"
+#include "gtkdragsource.h"
+#include "gtkdroptarget.h"
#include "gtkeditable.h"
#include "gtkemojichooser.h"
#include "gtkemojicompletion.h"
#include "gtkwindow.h"
#include "gtknative.h"
#include "gtkactionmuxerprivate.h"
-#include "gtkdragsource.h"
-#include "gtkdragdest.h"
-#include "gtkdragicon.h"
#include "a11y/gtktextaccessible.h"
int dnd_position; /* In chars, -1 == no DND cursor */
int drag_start_x;
int drag_start_y;
- int drop_position; /* where the drop should happen */
int insert_pos;
int selection_bound;
int scroll_offset;
static void gtk_text_root (GtkWidget *widget);
static gboolean gtk_text_drag_drop (GtkDropTarget *dest,
- GdkDrop *drop,
- int x,
- int y,
+ const GValue *value,
+ double x,
+ double y,
GtkText *text);
static gboolean gtk_text_drag_accept (GtkDropTarget *dest,
GdkDrop *drop,
GtkText *self);
-static void gtk_text_drag_motion (GtkDropTarget *dest,
- GdkDrop *drop,
- int x,
- int y,
+static GdkDragAction gtk_text_drag_motion (GtkDropTarget *dest,
+ double x,
+ double y,
GtkText *text);
static void gtk_text_drag_leave (GtkDropTarget *dest,
- GdkDrop *drop,
GtkText *text);
GtkGesture *gesture;
GtkEventController *controller;
int i;
- GtkDropTarget *dest;
+ GtkDropTarget *target;
gtk_widget_set_can_focus (GTK_WIDGET (self), TRUE);
gtk_widget_set_overflow (GTK_WIDGET (self), GTK_OVERFLOW_HIDDEN);
priv->selection_content = g_object_new (GTK_TYPE_TEXT_CONTENT, NULL);
GTK_TEXT_CONTENT (priv->selection_content)->self = self;
- dest = gtk_drop_target_new (gdk_content_formats_new_for_gtype (G_TYPE_STRING),
- GDK_ACTION_COPY | GDK_ACTION_MOVE);
- g_signal_connect (dest, "accept", G_CALLBACK (gtk_text_drag_accept), self);
- g_signal_connect (dest, "drag-motion", G_CALLBACK (gtk_text_drag_motion), self);
- g_signal_connect (dest, "drag-leave", G_CALLBACK (gtk_text_drag_leave), self);
- g_signal_connect (dest, "drag-drop", G_CALLBACK (gtk_text_drag_drop), self);
- gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (dest));
+ target = gtk_drop_target_new (G_TYPE_STRING, GDK_ACTION_COPY | GDK_ACTION_MOVE);
+ g_signal_connect (target, "accept", G_CALLBACK (gtk_text_drag_accept), self);
+ g_signal_connect (target, "enter", G_CALLBACK (gtk_text_drag_motion), self);
+ g_signal_connect (target, "motion", G_CALLBACK (gtk_text_drag_motion), self);
+ g_signal_connect (target, "leave", G_CALLBACK (gtk_text_drag_leave), self);
+ g_signal_connect (target, "drop", G_CALLBACK (gtk_text_drag_drop), self);
+ gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (target));
/* This object is completely private. No external entity can gain a reference
* to it; so we create it here and destroy it in finalize().
static void
gtk_text_drag_leave (GtkDropTarget *dest,
- GdkDrop *drop,
- GtkText *self)
+ GtkText *self)
{
GtkTextPrivate *priv = gtk_text_get_instance_private (self);
GtkWidget *widget = GTK_WIDGET (self);
gtk_widget_queue_draw (widget);
}
-static GdkDragAction
-gtk_text_get_action (GtkText *self,
- GdkDrop *drop)
+static gboolean
+gtk_text_drag_drop (GtkDropTarget *dest,
+ const GValue *value,
+ double x,
+ double y,
+ GtkText *self)
{
GtkTextPrivate *priv = gtk_text_get_instance_private (self);
- GdkDrag *drag = gdk_drop_get_drag (drop);
- GdkDragAction actions;
-
- actions = gdk_drop_get_actions (drop);
-
- if (drag == priv->drag &&
- actions & GDK_ACTION_MOVE)
- return GDK_ACTION_MOVE;
-
- if (actions & GDK_ACTION_COPY)
- return GDK_ACTION_COPY;
-
- if (actions & GDK_ACTION_MOVE)
- return GDK_ACTION_MOVE;
+ int drop_position;
+ int length;
+ const char *str;
- return 0;
-}
+ if (!priv->editable)
+ return FALSE;
-static void
-got_text (GObject *source,
- GAsyncResult *result,
- gpointer data)
-{
- GdkDrop *drop = GDK_DROP (source);
- GtkText *self = GTK_TEXT (data);
- GtkTextPrivate *priv = gtk_text_get_instance_private (self);
- char *str;
- GdkDragAction action;
+ drop_position = gtk_text_find_position (self, x + priv->scroll_offset);
- str = gdk_drop_read_text_finish (drop, result, NULL);
- action = gtk_text_get_action (self, drop);
+ str = g_value_get_string (value);
+ if (priv->truncate_multiline)
+ length = truncate_multiline (str);
+ else
+ length = -1;
- if (action && str)
+ if (priv->selection_bound == priv->current_pos ||
+ drop_position < priv->selection_bound ||
+ drop_position > priv->current_pos)
{
- int length = -1;
- int pos;
-
- if (priv->truncate_multiline)
- length = truncate_multiline (str);
-
- if (priv->selection_bound == priv->current_pos ||
- priv->drop_position < priv->selection_bound ||
- priv->drop_position > priv->current_pos)
- {
- gtk_text_insert_text (self, str, length, &priv->drop_position);
- }
- else
- {
- /* Replacing selection */
- begin_change (self);
- gtk_text_delete_selection (self);
- pos = MIN (priv->selection_bound, priv->current_pos);
- gtk_text_insert_text (self, str, length, &pos);
- end_change (self);
- }
-
- gdk_drop_finish (drop, action);
+ gtk_text_insert_text (self, str, length, &drop_position);
}
else
{
- /* Drag and drop didn't happen! */
- gdk_drop_finish (drop, 0);
- }
-
- g_free (str);
-}
-
-static gboolean
-gtk_text_drag_drop (GtkDropTarget *dest,
- GdkDrop *drop,
- int x,
- int y,
- GtkText *self)
-{
- GtkTextPrivate *priv = gtk_text_get_instance_private (self);
-
- if (priv->editable && gdk_drop_has_value (drop, G_TYPE_STRING))
- {
- priv->drop_position = gtk_text_find_position (self, x + priv->scroll_offset);
- gdk_drop_read_text_async (drop, NULL, got_text, self);
+ int pos;
+ /* Replacing selection */
+ begin_change (self);
+ gtk_text_delete_selection (self);
+ pos = MIN (priv->selection_bound, priv->current_pos);
+ gtk_text_insert_text (self, str, length, &pos);
+ end_change (self);
}
- else
- gdk_drop_finish (drop, 0);
return TRUE;
}
return gdk_content_formats_match (gtk_drop_target_get_formats (dest), gdk_drop_get_formats (drop));
}
-static void
-gtk_text_drag_motion (GtkDropTarget *dest,
- GdkDrop *drop,
- int x,
- int y,
- GtkText *self)
+static GdkDragAction
+gtk_text_drag_motion (GtkDropTarget *target,
+ double x,
+ double y,
+ GtkText *self)
{
GtkTextPrivate *priv = gtk_text_get_instance_private (self);
int new_position, old_position;
+ if (!priv->editable)
+ {
+ gtk_drop_target_reject (target);
+ return 0;
+ }
+
old_position = priv->dnd_position;
new_position = gtk_text_find_position (self, x + priv->scroll_offset);
- if (priv->editable)
+ if (priv->selection_bound == priv->current_pos ||
+ new_position < priv->selection_bound ||
+ new_position > priv->current_pos)
{
- if (priv->selection_bound == priv->current_pos ||
- new_position < priv->selection_bound ||
- new_position > priv->current_pos)
- {
- priv->dnd_position = new_position;
- }
- else
- {
- priv->dnd_position = -1;
- }
+ priv->dnd_position = new_position;
}
else
{
- /* Entry not editable, or no text */
priv->dnd_position = -1;
}
if (priv->dnd_position != old_position)
gtk_widget_queue_draw (GTK_WIDGET (self));
+
+ if (priv->drag)
+ return GDK_ACTION_MOVE;
+ else
+ return GDK_ACTION_COPY;
}
/* We display the cursor when
/* Target side drag signals */
static void gtk_text_view_drag_leave (GtkDropTarget *dest,
- GdkDrop *drop,
GtkTextView *text_view);
-static gboolean gtk_text_view_drag_motion (GtkDropTarget *dest,
- GdkDrop *drop,
- int x,
- int y,
+static GdkDragAction
+ gtk_text_view_drag_motion (GtkDropTarget *dest,
+ double x,
+ double y,
GtkTextView *text_view);
static gboolean gtk_text_view_drag_drop (GtkDropTarget *dest,
- GdkDrop *drop,
- int x,
- int y,
+ const GValue *value,
+ double x,
+ double y,
GtkTextView *text_view);
static gboolean gtk_text_view_popup_menu (GtkWidget *widget);
priv->scroll_after_paste = FALSE;
- dest = gtk_drop_target_new (gdk_content_formats_new_for_gtype (GTK_TYPE_TEXT_BUFFER), GDK_ACTION_COPY | GDK_ACTION_MOVE);
- g_signal_connect (dest, "drag-leave", G_CALLBACK (gtk_text_view_drag_leave), text_view);
- g_signal_connect (dest, "drag-motion", G_CALLBACK (gtk_text_view_drag_motion), text_view);
- g_signal_connect (dest, "drag-drop", G_CALLBACK (gtk_text_view_drag_drop), text_view);
+ dest = gtk_drop_target_new (G_TYPE_STRING, GDK_ACTION_COPY | GDK_ACTION_MOVE);
+ g_signal_connect (dest, "enter", G_CALLBACK (gtk_text_view_drag_motion), text_view);
+ g_signal_connect (dest, "motion", G_CALLBACK (gtk_text_view_drag_motion), text_view);
+ g_signal_connect (dest, "leave", G_CALLBACK (gtk_text_view_drag_leave), text_view);
+ g_signal_connect (dest, "drop", G_CALLBACK (gtk_text_view_drag_drop), text_view);
gtk_widget_add_controller (GTK_WIDGET (text_view), GTK_EVENT_CONTROLLER (dest));
controller = gtk_drop_controller_motion_new ();
static void
gtk_text_view_drag_leave (GtkDropTarget *dest,
- GdkDrop *drop,
GtkTextView *text_view)
{
GtkTextViewPrivate *priv = text_view->priv;
gtk_text_mark_set_visible (priv->dnd_mark, FALSE);
}
-static gboolean
+static GdkDragAction
gtk_text_view_drag_motion (GtkDropTarget *dest,
- GdkDrop *drop,
- int x,
- int y,
+ double x,
+ double y,
GtkTextView *text_view)
{
GtkTextViewPrivate *priv = text_view->priv;
if (can_accept)
{
gtk_text_mark_set_visible (priv->dnd_mark, cursor_visible (text_view));
- gdk_drop_status (drop, GDK_ACTION_COPY | GDK_ACTION_MOVE);
+ if (text_view->priv->drag)
+ return GDK_ACTION_MOVE;
+ else
+ return GDK_ACTION_COPY;
}
else
{
- gdk_drop_status (drop, 0);
gtk_text_mark_set_visible (priv->dnd_mark, FALSE);
+ return 0;
}
-
- /* TRUE return means don't propagate the drag motion to parent
- * widgets that may also be drop sites.
- */
- return TRUE;
}
-static GdkDragAction
-gtk_text_view_get_action (GtkTextView *textview,
- GdkDrop *drop)
-{
- GdkDrag *drag = gdk_drop_get_drag (drop);
- GdkDragAction actions;
-
- actions = gdk_drop_get_actions (drop);
-
- if (drag == textview->priv->drag &&
- actions & GDK_ACTION_MOVE)
- return GDK_ACTION_MOVE;
-
- if (actions & GDK_ACTION_COPY)
- return GDK_ACTION_COPY;
-
- if (actions & GDK_ACTION_MOVE)
- return GDK_ACTION_MOVE;
-
- return 0;
-}
-
-static void
-got_text (GObject *source,
- GAsyncResult *result,
- gpointer data)
+static gboolean
+gtk_text_view_drag_drop (GtkDropTarget *dest,
+ const GValue *value,
+ double x,
+ double y,
+ GtkTextView *text_view)
{
- GdkDrop *drop = GDK_DROP (source);
- GtkTextView *text_view = GTK_TEXT_VIEW (data);
GtkTextViewPrivate *priv = text_view->priv;
GtkTextBuffer *buffer;
- char *str;
GtkTextIter drop_point;
- GdkDragAction action;
-
- str = gdk_drop_read_text_finish (drop, result, NULL);
- if (!str)
- {
- gdk_drop_finish (drop, 0);
- return;
- }
buffer = get_buffer (text_view);
gtk_text_buffer_get_iter_at_mark (buffer, &drop_point, priv->dnd_mark);
- action = gtk_text_view_get_action (text_view, drop);
+ if (!gtk_text_iter_can_insert (&drop_point, priv->editable))
+ return FALSE;
gtk_text_buffer_begin_user_action (buffer);
if (!gtk_text_buffer_insert_interactive (buffer,
- &drop_point, (gchar *) str, -1,
+ &drop_point, (gchar *) g_value_get_string (value), -1,
text_view->priv->editable))
gtk_widget_error_bell (GTK_WIDGET (text_view));
- g_free (str);
-
gtk_text_buffer_get_iter_at_mark (buffer, &drop_point, priv->dnd_mark);
gtk_text_buffer_place_cursor (buffer, &drop_point);
gtk_text_buffer_end_user_action (buffer);
- gdk_drop_finish (drop, action);
-}
-
-static gboolean
-gtk_text_view_drag_drop (GtkDropTarget *dest,
- GdkDrop *drop,
- int x,
- int y,
- GtkTextView *text_view)
-{
- GtkTextViewPrivate *priv = text_view->priv;
- GtkTextIter drop_point;
- GtkTextBuffer *buffer = NULL;
-
- gtk_text_mark_set_visible (priv->dnd_mark, FALSE);
-
- buffer = get_buffer (text_view);
- gtk_text_buffer_get_iter_at_mark (buffer, &drop_point, priv->dnd_mark);
-
- if (!gtk_text_iter_can_insert (&drop_point, priv->editable))
- goto done;
-
- if (gtk_text_view_get_action (text_view, drop) == 0)
- goto done;
-
- if (gdk_drop_has_value (drop, G_TYPE_STRING))
- {
- gdk_drop_read_text_async (drop, NULL, got_text, text_view);
- return TRUE;
- }
-
-done:
- gdk_drop_finish (drop, 0);
return TRUE;
}
-
+
static void
gtk_text_view_set_hadjustment (GtkTextView *text_view,
GtkAdjustment *adjustment)
#include "gtkcssnumbervalueprivate.h"
#include "gtkcsscolorvalueprivate.h"
#include "gtkcssstylepropertyprivate.h"
-#include "gtkdragdest.h"
#include "gtkdragsource.h"
#include "gtkdragicon.h"
+#include "gtkdroptargetasync.h"
#include "gtkentryprivate.h"
#include "gtksearchentryprivate.h"
#include "gtkeventcontrollerkey.h"
GtkTreeRowReference *source_item;
GtkCssNode *cssnode;
- GtkDropTarget *dest;
+ GtkDropTargetAsync *dest;
GdkModifierType start_button_mask;
guint source_set : 1;
guint keycode,
GdkModifierType state,
GtkTreeView *tree_view);
-static void gtk_tree_view_focus_controller_focus_out (GtkEventController *focus,
- GtkTreeView *tree_view);
+static void gtk_tree_view_focus_controller_focus_out (GtkEventController *focus,
+ GtkTreeView *tree_view);
static gint gtk_tree_view_focus (GtkWidget *widget,
GtkDirectionType direction);
GtkTreePath *source_row);
/* Target side drag signals */
-static void gtk_tree_view_drag_leave (GtkDropTarget *dest,
- GdkDrop *drop,
- GtkTreeView *tree_view);
-static void gtk_tree_view_drag_motion (GtkDropTarget *dest,
- GdkDrop *drop,
- int x,
- int y,
- GtkTreeView *tree_view);
-static gboolean gtk_tree_view_drag_drop (GtkDropTarget *dest,
- GdkDrop *drop,
- int x,
- int y,
- GtkTreeView *tree_view);
-static void gtk_tree_view_drag_data_received (GObject *source,
- GAsyncResult *result,
- gpointer data);
+static void gtk_tree_view_drag_leave (GtkDropTargetAsync *dest,
+ GdkDrop *drop,
+ GtkTreeView *tree_view);
+static GdkDragAction gtk_tree_view_drag_motion (GtkDropTargetAsync *dest,
+ GdkDrop *drop,
+ double x,
+ double y,
+ GtkTreeView *tree_view);
+static gboolean gtk_tree_view_drag_drop (GtkDropTargetAsync *dest,
+ GdkDrop *drop,
+ double x,
+ double y,
+ GtkTreeView *tree_view);
+static void gtk_tree_view_drag_data_received (GObject *source,
+ GAsyncResult *result,
+ gpointer data);
/* tree_model signals */
static gboolean gtk_tree_view_real_move_cursor (GtkTreeView *tree_view,
/* Returns TRUE if event should not be propagated to parent widgets */
static gboolean
-set_destination_row (GtkTreeView *tree_view,
- GtkDropTarget *dest,
+set_destination_row (GtkTreeView *tree_view,
+ GtkDropTargetAsync *dest,
/* coordinates relative to the widget */
- gint x,
- gint y,
- GdkDragAction *suggested_action,
- GType *target)
+ gint x,
+ gint y,
+ GdkDragAction *suggested_action,
+ GType *target)
{
GtkTreePath *path = NULL;
GtkTreeViewDropPosition pos;
return FALSE; /* no longer a drop site */
}
- formats = gtk_drop_target_get_formats (dest);
+ formats = gtk_drop_target_async_get_formats (dest);
*target = gdk_content_formats_match_gtype (formats, formats);
if (*target == G_TYPE_INVALID)
return FALSE;
}
static void
-gtk_tree_view_drag_leave (GtkDropTarget *dest,
- GdkDrop *drop,
- GtkTreeView *tree_view)
+gtk_tree_view_drag_leave (GtkDropTargetAsync *dest,
+ GdkDrop *drop,
+ GtkTreeView *tree_view)
{
/* unset any highlight row */
gtk_tree_view_set_drag_dest_row (tree_view,
}
-static void
-gtk_tree_view_drag_motion (GtkDropTarget *dest,
- GdkDrop *drop,
- int x,
- int y,
- GtkTreeView *tree_view)
+static GdkDragAction
+gtk_tree_view_drag_motion (GtkDropTargetAsync *dest,
+ GdkDrop *drop,
+ double x,
+ double y,
+ GtkTreeView *tree_view)
{
gboolean empty;
GtkTreePath *path = NULL;
GType target;
if (!set_destination_row (tree_view, dest, x, y, &suggested_action, &target))
- {
- gdk_drop_status (drop, 0);
- return;
- }
+ return 0;
tree_view->event_last_x = x;
tree_view->event_last_y = y;
if (path == NULL && !empty)
{
- /* Can't drop here. */
- gdk_drop_status (drop, 0);
+ suggested_action = 0;
}
else
{
else
{
set_status_pending (drop, 0);
- gdk_drop_status (drop, suggested_action);
}
}
if (path)
gtk_tree_path_free (path);
+
+ return suggested_action;
}
static gboolean
-gtk_tree_view_drag_drop (GtkDropTarget *dest,
- GdkDrop *drop,
- int x,
- int y,
- GtkTreeView *tree_view)
+gtk_tree_view_drag_drop (GtkDropTargetAsync *dest,
+ GdkDrop *drop,
+ double x,
+ double y,
+ GtkTreeView *tree_view)
{
GtkTreePath *path;
GdkDragAction suggested_action = 0;
}
}
- gdk_drop_status (drop, suggested_action);
-
if (path)
gtk_tree_path_free (path);
di = ensure_info (tree_view);
di->dest_set = TRUE;
- di->dest = gtk_drop_target_new (gdk_content_formats_ref (formats), actions);
+ di->dest = gtk_drop_target_async_new (gdk_content_formats_ref (formats), actions);
g_signal_connect (di->dest, "drag-leave", G_CALLBACK (gtk_tree_view_drag_leave), tree_view);
+ g_signal_connect (di->dest, "drag-enter", G_CALLBACK (gtk_tree_view_drag_motion), tree_view);
g_signal_connect (di->dest, "drag-motion", G_CALLBACK (gtk_tree_view_drag_motion), tree_view);
- g_signal_connect (di->dest, "drag-drop", G_CALLBACK (gtk_tree_view_drag_drop), tree_view);
+ g_signal_connect (di->dest, "drop", G_CALLBACK (gtk_tree_view_drag_drop), tree_view);
gtk_widget_add_controller (GTK_WIDGET (tree_view), GTK_EVENT_CONTROLLER (di->dest));
g_object_ref (di->dest);
{
GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
- g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+ if (!GTK_IS_WIDGET (widget)) return FALSE;
return priv->has_grab;
}
#include "gtkcsscolorvalueprivate.h"
#include "gtkcssshadowvalueprivate.h"
#include "gtkcssstylepropertyprivate.h"
-#include "gtkdragdest.h"
+#include "gtkdroptargetasync.h"
#include "gtkeventcontrollerfocus.h"
#include "gtkeventcontrollerkey.h"
#include "gtkeventcontrollermotion.h"
GtkConstraintSolver *constraint_solver;
} GtkWindowPrivate;
-#ifdef GDK_WINDOWING_X11
-static const char *dnd_dest_targets [] = {
- "application/x-rootwindow-drop"
-};
-#endif
-
enum {
SET_FOCUS,
ACTIVATE_FOCUS,
gtk_window_real_activate_default (GTK_WINDOW (widget));
}
+static gboolean
+gtk_window_accept_rootwindow_drop (GtkDropTargetAsync *self,
+ GdkDrop *drop,
+ double x,
+ double y,
+ gpointer unused)
+{
+ gdk_drop_finish (drop, GDK_ACTION_MOVE);
+
+ return TRUE;
+}
+
static void
gtk_window_init (GtkWindow *window)
{
GdkSeat *seat;
GtkEventController *motion_controller;
GtkEventController *controller;
-#ifdef GDK_WINDOWING_X11
- GtkDropTarget *dest;
-#endif
+ GtkDropTargetAsync *target;
widget = GTK_WIDGET (window);
priv->scale = gtk_widget_get_scale_factor (widget);
-#ifdef GDK_WINDOWING_X11
- dest = gtk_drop_target_new (gdk_content_formats_new (dnd_dest_targets, G_N_ELEMENTS (dnd_dest_targets)), GDK_ACTION_MOVE);
- gtk_widget_add_controller (GTK_WIDGET (window), GTK_EVENT_CONTROLLER (dest));
-#endif
+ target = gtk_drop_target_async_new (gdk_content_formats_new ((const char*[1]) { "application/x-rootwindow-drop" }, 1),
+ GDK_ACTION_MOVE);
+ g_signal_connect (target, "drop", G_CALLBACK (gtk_window_accept_rootwindow_drop), NULL);
+ gtk_widget_add_controller (GTK_WIDGET (window), GTK_EVENT_CONTROLLER (target));
seat = gdk_display_get_default_seat (gtk_widget_get_display (widget));
g_signal_connect (seat, "device-removed",
'gtkcssvalue.c',
'gtkcsswidgetnode.c',
'gtkcustomlayout.c',
+ 'gtkdrop.c',
'gtkfilechooserembed.c',
'gtkfilechooserentry.c',
'gtkfilechoosererrorstack.c',
'gtkcontainer.c',
'gtkcssprovider.c',
'gtkdialog.c',
- 'gtkdragdest.c',
'gtkdragicon.c',
'gtkdragsource.c',
'gtkdrawingarea.c',
'gtkdropcontrollermotion.c',
+ 'gtkdroptarget.c',
+ 'gtkdroptargetasync.c',
'gtkeditable.c',
'gtkemojichooser.c',
'gtkemojicompletion.c',
'gtkcustomlayout.h',
'gtkdebug.h',
'gtkdialog.h',
- 'gtkdragdest.h',
'gtkdragicon.h',
'gtkdragsource.h',
'gtkdrawingarea.h',
'gtkdropcontrollermotion.h',
+ 'gtkdroptarget.h',
+ 'gtkdroptargetasync.h',
'gtkeditable.h',
'gtkemojichooser.h',
'gtkentry.h',
GdkPixbuf *trashcan_open;
GdkPixbuf *trashcan_closed;
-gboolean have_drag;
-static const char *target_table[] = {
- "STRING",
- "text/plain",
- "application/x-rootwindow-drop"
-};
+static GdkDragAction
+action_make_unique (GdkDragAction action)
+{
+ if (gdk_drag_action_is_unique (action))
+ return action;
-static guint n_targets = sizeof(target_table) / sizeof(target_table[0]);
+ if (action & GDK_ACTION_COPY)
+ return GDK_ACTION_COPY;
-void
-target_drag_leave (GtkDropTarget *dest,
- GdkDrop *drop,
- GtkWidget *widget)
-{
- g_print("leave\n");
- have_drag = FALSE;
- gtk_image_set_from_pixbuf (GTK_IMAGE (widget), trashcan_closed);
+ if (action & GDK_ACTION_MOVE)
+ return GDK_ACTION_MOVE;
+
+ if (action & GDK_ACTION_LINK)
+ return GDK_ACTION_LINK;
+
+ g_assert_not_reached ();
+ return 0;
}
-gboolean
-target_drag_motion (GtkDropTarget *dest,
- GdkDrop *drop,
- int x,
- int y,
- GtkWidget *widget)
+GdkDragAction
+trash_drag_enter (GtkDropTarget *dest,
+ GdkDrop *drop,
+ double x,
+ double y,
+ GtkWidget *widget)
{
char *s;
- if (!have_drag)
- {
- have_drag = TRUE;
- gtk_image_set_from_pixbuf (GTK_IMAGE (widget), trashcan_open);
- }
+ gtk_image_set_from_pixbuf (GTK_IMAGE (widget), trashcan_open);
s = gdk_content_formats_to_string (gdk_drop_get_formats (drop));
- g_print ("%s\n", s);
-
- gdk_drop_status (drop, GDK_ACTION_ALL);
+ g_print ("trash enter: %s\n", s);
+ g_free (s);
- return TRUE;
+ return action_make_unique (gdk_drop_get_actions (drop));;
}
-static void
-got_text_in_target (GObject *object,
- GAsyncResult *result,
- gpointer data)
-{
- char *str;
-
- str = gdk_drop_read_text_finish (GDK_DROP (object), result, NULL);
- if (str)
- {
- g_print ("Received \"%s\" in target\n", str);
- g_free (str);
- }
-
- gdk_drop_finish (GDK_DROP (object), GDK_ACTION_MOVE);
-}
-
-gboolean
-target_drag_drop (GtkDropTarget *dest,
+GdkDragAction
+trash_drag_leave (GtkDropTarget *dest,
GdkDrop *drop,
- int x,
- int y,
- GtkWidget *widget)
+ GtkWidget *widget)
{
- GdkContentFormats *formats;
- const char *format;
-
- g_print("drop\n");
- have_drag = FALSE;
+ char *s;
gtk_image_set_from_pixbuf (GTK_IMAGE (widget), trashcan_closed);
- formats = gdk_drop_get_formats (drop);
- format = gdk_content_formats_match_mime_type (formats, formats);
- if (format)
- {
- gdk_drop_read_text_async (drop, NULL, got_text_in_target, widget);
- return TRUE;
- }
-
- gdk_drop_status (drop, 0);
+ s = gdk_content_formats_to_string (gdk_drop_get_formats (drop));
+ g_print ("trash leave: %s\n", s);
+ g_free (s);
- return FALSE;
+ return action_make_unique (gdk_drop_get_actions (drop));
}
-static GdkDragAction
-action_make_unique (GdkDragAction action)
+gboolean
+trash_drag_drop (GtkDropTarget *dest,
+ GdkDrop *drop,
+ double x,
+ double y,
+ GtkWidget *widget)
{
- if (gdk_drag_action_is_unique (action))
- return action;
-
- if (action & GDK_ACTION_COPY)
- return GDK_ACTION_COPY;
+ char *s;
- if (action & GDK_ACTION_MOVE)
- return GDK_ACTION_MOVE;
-
- if (action & GDK_ACTION_LINK)
- return GDK_ACTION_LINK;
-
- g_assert_not_reached ();
- return 0;
-}
+ s = gdk_content_formats_to_string (gdk_drop_get_formats (drop));
+ g_print ("trash drop: %s\n", s);
+ g_free (s);
-static void
-got_text (GObject *object,
- GAsyncResult *result,
- gpointer data)
-{
- char *str;
+ gdk_drop_finish (drop, action_make_unique (gdk_drop_get_actions (drop)));
- str = gdk_drop_read_text_finish (GDK_DROP (object), result, NULL);
- if (str)
- {
- g_print ("Received \"%s\" in label\n", str);
- g_free (str);
- }
+ return TRUE;
}
-
-void
+
+gboolean
label_drag_drop (GtkDropTarget *dest,
- GdkDrop *drop,
+ const GValue *value,
int x,
int y,
GtkWidget *widget)
{
- gdk_drop_read_text_async (drop, NULL, got_text, widget);
- GdkDragAction action = action_make_unique (gdk_drop_get_actions (drop));
- gdk_drop_finish (drop, action);
+ g_print ("Received \"%s\" in label\n", g_value_get_string (value));
+ return TRUE;
}
/* The following is a rather elaborate example demonstrating/testing
return FALSE;
}
-gboolean
-popup_motion (GtkDropTarget *dest,
- GdkDrop *drop)
-{
- gdk_drop_status (drop, GDK_ACTION_COPY);
- return TRUE;
-}
-
void
popup_enter (GtkDropTarget *dest)
{
-g_print ("popup enter\n");
+ g_print ("popup enter\n");
if (!in_popup)
{
in_popup = TRUE;
}
static gboolean
-popup_drop (GtkDropTarget *dest,
- GdkDrop *drop)
+popup_drop (GtkDropTarget *dest)
{
- gdk_drop_finish (drop, GDK_ACTION_COPY);
popdown_cb (NULL);
return TRUE;
}
GtkWidget *button;
GtkWidget *grid;
int i, j;
- GdkContentFormats *targets;
popup_window = gtk_window_new ();
grid = gtk_grid_new ();
- targets = gdk_content_formats_new_for_gtype (G_TYPE_STRING);
for (i=0; i<3; i++)
for (j=0; j<3; j++)
gtk_widget_set_vexpand (button, TRUE);
gtk_grid_attach (GTK_GRID (grid), button, i, j, 1, 1);
- dest = gtk_drop_target_new (targets, GDK_ACTION_COPY | GDK_ACTION_MOVE);
- g_signal_connect (dest, "accept", G_CALLBACK (popup_motion), NULL);
- g_signal_connect (dest, "drag-enter", G_CALLBACK (popup_enter), NULL);
- g_signal_connect (dest, "drag-leave", G_CALLBACK (popup_leave), NULL);
- g_signal_connect (dest, "drag-drop", G_CALLBACK (popup_drop), NULL);
+ dest = gtk_drop_target_new (G_TYPE_STRING, GDK_ACTION_COPY | GDK_ACTION_MOVE);
+ g_signal_connect (dest, "enter", G_CALLBACK (popup_enter), NULL);
+ g_signal_connect (dest, "leave", G_CALLBACK (popup_leave), NULL);
+ g_signal_connect (dest, "drop", G_CALLBACK (popup_drop), NULL);
gtk_widget_add_controller (button, GTK_EVENT_CONTROLLER (dest));
}
gtk_container_add (GTK_CONTAINER (popup_window), grid);
- gdk_content_formats_unref (targets);
-
}
gtk_widget_show (popup_window);
popped_up = TRUE;
}
void
-popsite_enter (GtkDropTarget *dest)
+popsite_enter (GtkDropControllerMotion *motion)
{
-g_print ("popsite enter\n");
+ g_print ("popsite enter\n");
if (!popup_timer)
popup_timer = g_timeout_add (500, popup_cb, NULL);
-
}
void
-popsite_leave (GtkDropTarget *dest)
+popsite_leave (GtkDropControllerMotion *motion)
{
-g_print ("popsite leave\n");
+ g_print ("popsite leave\n");
if (popup_timer)
{
g_source_remove (popup_timer);
GdkTexture *texture;
GdkContentProvider *content;
GtkDragSource *source;
- GdkContentFormats *targets;
GtkDropTarget *dest;
+ GtkDropTargetAsync *async;
+ GtkEventController *controller;
gboolean done = FALSE;
test_init ();
label = gtk_label_new ("Drop Here\n");
- targets = gdk_content_formats_new (target_table, n_targets - 1); /* no rootwin */
- dest = gtk_drop_target_new (gdk_content_formats_ref (targets), GDK_ACTION_COPY | GDK_ACTION_MOVE);
- g_signal_connect (dest, "drag-drop", G_CALLBACK (label_drag_drop), NULL);
+ dest = gtk_drop_target_new (G_TYPE_STRING, GDK_ACTION_COPY | GDK_ACTION_MOVE);
+ g_signal_connect (dest, "drop", G_CALLBACK (label_drag_drop), NULL);
gtk_widget_add_controller (label, GTK_EVENT_CONTROLLER (dest));
gtk_widget_set_hexpand (label, TRUE);
label = gtk_label_new ("Popup\n");
- dest = gtk_drop_target_new (targets, GDK_ACTION_COPY | GDK_ACTION_MOVE);
- g_signal_connect (dest, "accept", G_CALLBACK (popsite_motion), NULL);
- g_signal_connect (dest, "drag-enter", G_CALLBACK (popsite_enter), NULL);
- g_signal_connect (dest, "drag-leave", G_CALLBACK (popsite_leave), NULL);
- gtk_widget_add_controller (label, GTK_EVENT_CONTROLLER (dest));
+ controller = gtk_drop_controller_motion_new ();
+ g_signal_connect (controller, "enter", G_CALLBACK (popsite_enter), NULL);
+ g_signal_connect (controller, "leave", G_CALLBACK (popsite_leave), NULL);
+ gtk_widget_add_controller (label, controller);
gtk_widget_set_hexpand (label, TRUE);
gtk_widget_set_vexpand (label, TRUE);
gtk_grid_attach (GTK_GRID (grid), label, 1, 1, 1, 1);
pixmap = gtk_image_new_from_pixbuf (trashcan_closed);
- dest = gtk_drop_target_new (NULL, 0);
- g_signal_connect (dest, "drag-leave", G_CALLBACK (target_drag_leave), pixmap);
- g_signal_connect (dest, "accept", G_CALLBACK (target_drag_motion), pixmap);
- g_signal_connect (dest, "drag-drop", G_CALLBACK (target_drag_drop), pixmap);
- gtk_widget_add_controller (pixmap, GTK_EVENT_CONTROLLER (dest));
+ async = gtk_drop_target_async_new (NULL, 0);
+ g_signal_connect (async, "drag-enter", G_CALLBACK (trash_drag_enter), pixmap);
+ g_signal_connect (async, "drag-leave", G_CALLBACK (trash_drag_leave), pixmap);
+ g_signal_connect (async, "drop", G_CALLBACK (trash_drag_drop), pixmap);
+ gtk_widget_add_controller (pixmap, GTK_EVENT_CONTROLLER (async));
gtk_widget_set_hexpand (pixmap, TRUE);
gtk_widget_set_vexpand (pixmap, TRUE);
perform_drop (GdkDrop *drop,
GtkWidget *image)
{
- if (gdk_drop_has_value (drop, GDK_TYPE_TEXTURE))
+ if (gdk_content_formats_contain_gtype (gdk_drop_get_formats (drop), GDK_TYPE_TEXTURE))
gdk_drop_read_value_async (drop, GDK_TYPE_TEXTURE, G_PRIORITY_DEFAULT, NULL, got_texture, image);
else
{
static gboolean
delayed_deny (gpointer data)
{
- GtkDropTarget *dest = data;
+ GtkDropTargetAsync *dest = data;
GtkWidget *image = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (dest));
GdkDrop *drop = GDK_DROP (g_object_get_data (G_OBJECT (image), "drop"));
if (drop)
{
g_print ("denying drop, late\n");
- gtk_drop_target_deny_drop (dest, drop);
+ gtk_drop_target_async_reject_drop (dest, drop);
}
return G_SOURCE_REMOVE;
}
static gboolean
-image_drag_motion (GtkDropTarget *dest,
- GdkDrop *drop,
- gpointer data)
+image_drag_accept (GtkDropTargetAsync *dest,
+ GdkDrop *drop,
+ gpointer data)
{
GtkWidget *image = data;
g_object_set_data_full (G_OBJECT (image), "drop", g_object_ref (drop), g_object_unref);
g_timeout_add (1000, delayed_deny, dest);
- gdk_drop_status (drop, gtk_drop_target_get_actions (dest));
-
return TRUE;
}
static gboolean
image_drag_drop (GtkDropTarget *dest,
GdkDrop *drop,
- int x,
- int y,
+ double x,
+ double y,
gpointer data)
{
GtkWidget *image = data;
{
GtkWidget *image;
GtkDragSource *source;
- GtkDropTarget *dest;
+ GtkDropTargetAsync *dest;
GdkContentFormats *formats;
GdkContentFormatsBuilder *builder;
g_signal_connect (source, "drag-cancel", G_CALLBACK (drag_cancel), NULL);
gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (source));
- dest = gtk_drop_target_new (formats, GDK_ACTION_COPY|GDK_ACTION_MOVE|GDK_ACTION_ASK);
- g_signal_connect (dest, "accept", G_CALLBACK (image_drag_motion), image);
- g_signal_connect (dest, "drag-drop", G_CALLBACK (image_drag_drop), image);
+ dest = gtk_drop_target_async_new (formats, GDK_ACTION_COPY|GDK_ACTION_MOVE|GDK_ACTION_ASK);
+ g_signal_connect (dest, "accept", G_CALLBACK (image_drag_accept), image);
+ g_signal_connect (dest, "drop", G_CALLBACK (image_drag_drop), image);
gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (dest));
return image;
drag_end (source, drag);
}
-typedef struct {
- GtkWidget *canvas;
- double x;
- double y;
-} DropData;
-
typedef struct {
double x, y;
double angle;
gsk_transform_unref (transform);
}
-static void
-got_data (GObject *source,
- GAsyncResult *result,
- gpointer user_data)
+static gboolean
+drag_drop (GtkDropTarget *target,
+ const GValue *value,
+ double x,
+ double y)
{
- GdkDrop *drop = GDK_DROP (source);
- DropData *data = user_data;
GtkWidget *item;
- const GValue *value;
TransformData *transform_data;
GtkWidget *canvas;
GtkWidget *last_child;
- value = gdk_drop_read_value_finish (drop, result, NULL);
- if (value == NULL)
- {
- gdk_drop_finish (drop, 0);
- return;
- }
-
item = g_value_get_object (value);
-
transform_data = g_object_get_data (G_OBJECT (item), "transform-data");
- transform_data->x = data->x;
- transform_data->y = data->y;
+ transform_data->x = x;
+ transform_data->y = y;
canvas = gtk_widget_get_parent (item);
last_child = gtk_widget_get_last_child (canvas);
apply_transform (item);
- gdk_drop_finish (drop, GDK_ACTION_MOVE);
-
- g_free (data);
-}
-
-static gboolean
-drag_drop (GtkDropTarget *dest,
- GdkDrop *drop,
- int x,
- int y)
-{
- DropData *data;
-
- data = g_new (DropData, 1);
- data->canvas = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (dest));
- data->x = x;
- data->y = y;
-
- gdk_drop_read_value_async (drop, GTK_TYPE_WIDGET, G_PRIORITY_DEFAULT, NULL, got_data, data);
-
return TRUE;
}
g_signal_connect (source, "drag-cancel", G_CALLBACK (drag_cancel), NULL);
gtk_widget_add_controller (canvas, GTK_EVENT_CONTROLLER (source));
- dest = gtk_drop_target_new (gdk_content_formats_new_for_gtype (GTK_TYPE_WIDGET), GDK_ACTION_MOVE);
- g_signal_connect (dest, "drag-drop", G_CALLBACK (drag_drop), NULL);
+ dest = gtk_drop_target_new (GTK_TYPE_WIDGET, GDK_ACTION_MOVE);
+ g_signal_connect (dest, "drop", G_CALLBACK (drag_drop), NULL);
gtk_widget_add_controller (canvas, GTK_EVENT_CONTROLLER (dest));
return canvas;
g_free (css);
}
-static void
-got_color (GObject *source,
- GAsyncResult *result,
- gpointer data)
+static gboolean
+item_drag_drop (GtkDropTarget *dest,
+ const GValue *value,
+ double x,
+ double y)
{
- GdkDrop *drop = GDK_DROP (source);
- GtkDropTarget *dest = data;
GtkWidget *item = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (dest));
- const GValue *value;
- GdkRGBA *color;
-
- value = gdk_drop_read_value_finish (drop, result, NULL);
- color = g_value_get_boxed (value);
- set_color (item, color);
- gdk_drop_finish (drop, GDK_ACTION_COPY);
-}
+ set_color (item, g_value_get_boxed (value));
-static gboolean
-item_drag_drop (GtkDropTarget *dest,
- GdkDrop *drop,
- int x,
- int y)
-{
- gdk_drop_read_value_async (drop, GDK_TYPE_RGBA, G_PRIORITY_DEFAULT, NULL, got_color, dest);
return TRUE;
}
TransformData *transform_data;
GdkRGBA rgba;
GtkDropTarget *dest;
- GdkContentFormats *formats;
GtkGesture *gesture;
label = g_strdup_printf ("Item %d", i);
g_free (label);
g_free (id);
- formats = gdk_content_formats_new_for_gtype (GDK_TYPE_RGBA);
- dest = gtk_drop_target_new (formats, GDK_ACTION_COPY);
- g_signal_connect (dest, "drag-drop", G_CALLBACK (item_drag_drop), NULL);
+ dest = gtk_drop_target_new (GDK_TYPE_RGBA, GDK_ACTION_COPY);
+ g_signal_connect (dest, "drop", G_CALLBACK (item_drag_drop), NULL);
gtk_widget_add_controller (widget, GTK_EVENT_CONTROLLER (dest));
- gdk_content_formats_unref (formats);
gesture = gtk_gesture_rotate_new ();
g_signal_connect (gesture, "angle-changed", G_CALLBACK (angle_changed), NULL);
g_object_unref (paintable);
}
-static void
-got_row (GObject *src,
- GAsyncResult *result,
- gpointer data)
+static gboolean
+drag_drop (GtkDropTarget *dest,
+ const GValue *value,
+ double x,
+ double y,
+ gpointer data)
{
- GdkDrop *drop = GDK_DROP (src);
GtkWidget *target = data;
GtkWidget *source;
int pos;
- source = g_value_get_object (gdk_drop_read_value_finish (drop, result, NULL));
+ source = g_value_get_object (value);
if (source == NULL)
- {
- gdk_drop_finish (drop, 0);
- return;
- }
+ return FALSE;
pos = gtk_list_box_row_get_index (GTK_LIST_BOX_ROW (target));
if (source == target)
- {
- gdk_drop_finish (drop, 0);
- return;
- }
+ return FALSE;
g_object_ref (source);
gtk_container_remove (GTK_CONTAINER (gtk_widget_get_parent (source)), source);
gtk_list_box_insert (GTK_LIST_BOX (gtk_widget_get_parent (target)), source, pos);
g_object_unref (source);
- gdk_drop_finish (drop, GDK_ACTION_MOVE);
-}
-
-static gboolean
-drag_drop (GtkDropTarget *dest,
- GdkDrop *drop,
- int x,
- int y,
- gpointer data)
-{
- gdk_drop_read_value_async (drop, GTK_TYPE_LIST_BOX_ROW, G_PRIORITY_DEFAULT, NULL, got_row, data);
-
return TRUE;
}
g_signal_connect (source, "prepare", G_CALLBACK (prepare), row);
gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (source));
- dest = gtk_drop_target_new (gdk_content_formats_new_for_gtype (GTK_TYPE_LIST_BOX_ROW), GDK_ACTION_MOVE);
- g_signal_connect (dest, "drag-drop", G_CALLBACK (drag_drop), row);
+ dest = gtk_drop_target_new (GTK_TYPE_LIST_BOX_ROW, GDK_ACTION_MOVE);
+ g_signal_connect (dest, "drop", G_CALLBACK (drag_drop), row);
gtk_widget_add_controller (GTK_WIDGET (row), GTK_EVENT_CONTROLLER (dest));
return row;
NULL
};
-static const char *button_targets[] = {
- "GTK_NOTEBOOK_TAB"
-};
-
static GtkNotebook*
window_creation_function (GtkNotebook *source_notebook,
GtkWidget *child,
static gboolean
remove_in_idle (gpointer data)
{
- GtkWidget *child = data;
+ GtkNotebookPage *page = data;
+ GtkWidget *child = gtk_notebook_page_get_child (page);
GtkWidget *parent = gtk_widget_get_ancestor (child, GTK_TYPE_NOTEBOOK);
GtkWidget *tab_label;
return G_SOURCE_REMOVE;
}
-static void
-got_page (GObject *source,
- GAsyncResult *result,
- gpointer data)
-{
- GdkDrop *drop = GDK_DROP (source);
- GInputStream *stream;
- const char *mime_type;
-
- stream = gdk_drop_read_finish (drop, result, &mime_type, NULL);
-
- if (stream)
- {
- GBytes *bytes;
- GtkWidget **child;
-
- bytes = g_input_stream_read_bytes (stream, sizeof (gpointer), NULL, NULL);
- child = (gpointer)g_bytes_get_data (bytes, NULL);
-
- g_idle_add (remove_in_idle, *child);
-
- gdk_drop_finish (drop, GDK_ACTION_MOVE);
-
- g_bytes_unref (bytes);
- g_object_unref (stream);
- }
- else
- gdk_drop_finish (drop, 0);
-}
-
static gboolean
on_button_drag_drop (GtkDropTarget *dest,
- GdkDrop *drop,
+ const GValue *value,
+ double x,
+ double y,
gpointer user_data)
{
- gdk_drop_read_async (drop, (const char *[]) { "GTK_NOTEBOOK_TAB", NULL }, G_PRIORITY_DEFAULT, NULL, got_page, NULL);
+ GtkNotebookPage *page;
- gdk_drop_finish (drop, GDK_ACTION_MOVE);
+ page = g_value_get_object (value);
+ g_idle_add (remove_in_idle, page);
return TRUE;
}
button = gtk_button_new_with_mnemonic ("_Delete");
- dest = gtk_drop_target_new (gdk_content_formats_new (button_targets, G_N_ELEMENTS (button_targets)), GDK_ACTION_MOVE);
- g_signal_connect (dest, "drag-drop", G_CALLBACK (on_button_drag_drop), NULL);
+ dest = gtk_drop_target_new (GTK_TYPE_NOTEBOOK_PAGE, GDK_ACTION_MOVE);
+ g_signal_connect (dest, "drop", G_CALLBACK (on_button_drag_drop), NULL);
gtk_widget_add_controller (button, GTK_EVENT_CONTROLLER (dest));
return button;
return GTK_WIDGET (tv);
}
-static void
-got_text (GObject *source,
- GAsyncResult *result,
- gpointer data)
-{
- GdkDrop *drop = GDK_DROP (source);
- GtkWidget *widget = data;
- const GValue *value;
-
- value = gdk_drop_read_value_finish (drop, result, NULL);
- if (value == NULL)
- return;
-
- gtk_label_set_label (GTK_LABEL (widget), g_value_get_string (value));
-}
-
static void
drag_drop (GtkDropTarget *dest,
- GdkDrop *drop,
+ const GValue *value,
int x,
int y,
gpointer dada)
{
GtkWidget *widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (dest));
- gdk_drop_read_value_async (drop, G_TYPE_STRING, G_PRIORITY_DEFAULT, NULL, got_text, widget);
+ gtk_label_set_label (GTK_LABEL (widget), g_value_get_string (value));
}
static GtkWidget *
GtkDropTarget *dest;
label = gtk_label_new ("Drop here");
- dest = gtk_drop_target_new (gdk_content_formats_new_for_gtype (G_TYPE_STRING), GDK_ACTION_COPY);
- g_signal_connect (dest, "drag-drop", G_CALLBACK (drag_drop), NULL);
+ dest = gtk_drop_target_new (G_TYPE_STRING, GDK_ACTION_COPY);
+ g_signal_connect (dest, "drop", G_CALLBACK (drag_drop), NULL);
gtk_widget_add_controller (label, GTK_EVENT_CONTROLLER (dest));
return label;
/* These are set in init() */
if ((g_type_is_a (type, GDK_TYPE_CLIPBOARD) ||
- g_type_is_a (type, GDK_TYPE_CONTENT_PROVIDER)) &&
+ g_type_is_a (type, GDK_TYPE_CONTENT_PROVIDER) ||
+ g_type_is_a (type, GTK_TYPE_DROP_TARGET)) &&
strcmp (pspec->name, "formats") == 0)
continue;